Coverage Report

Created: 2026-04-01 06:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source3/modules/vfs_default.c
Line
Count
Source
1
/*
2
   Unix SMB/CIFS implementation.
3
   Wrap disk only vfs functions to sidestep dodgy compilers.
4
   Copyright (C) Tim Potter 1998
5
   Copyright (C) Jeremy Allison 2007
6
7
   This program is free software; you can redistribute it and/or modify
8
   it under the terms of the GNU General Public License as published by
9
   the Free Software Foundation; either version 3 of the License, or
10
   (at your option) any later version.
11
12
   This program is distributed in the hope that it will be useful,
13
   but WITHOUT ANY WARRANTY; without even the implied warranty of
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
   GNU General Public License for more details.
16
17
   You should have received a copy of the GNU General Public License
18
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
*/
20
21
#include "includes.h"
22
#include "system/time.h"
23
#include "system/filesys.h"
24
#include "smbd/smbd.h"
25
#include "smbd/globals.h"
26
#include "ntioctl.h"
27
#include "smbprofile.h"
28
#include "../libcli/security/security.h"
29
#include "passdb/lookup_sid.h"
30
#include "source3/include/msdfs.h"
31
#include "librpc/gen_ndr/ndr_dfsblobs.h"
32
#include "lib/util/tevent_unix.h"
33
#include "lib/util/tevent_ntstatus.h"
34
#include "lib/util/sys_rw.h"
35
#include "lib/pthreadpool/pthreadpool_tevent.h"
36
#include "librpc/gen_ndr/ndr_ioctl.h"
37
#include "offload_token.h"
38
#include "util_reparse.h"
39
#include "lib/util/string_wrappers.h"
40
#include "lib/util/statvfs.h"
41
42
#undef DBGC_CLASS
43
0
#define DBGC_CLASS DBGC_VFS
44
45
/* Check for NULL pointer parameters in vfswrap_* functions */
46
47
/* We don't want to have NULL function pointers lying around.  Someone
48
   is sure to try and execute them.  These stubs are used to prevent
49
   this possibility. */
50
51
static int vfswrap_connect(vfs_handle_struct *handle, const char *service, const char *user)
52
0
{
53
0
  bool bval;
54
55
0
  handle->conn->have_proc_fds = sys_have_proc_fds();
56
#ifdef DISABLE_PROC_FDS
57
  handle->conn->have_proc_fds = false;
58
#endif
59
60
  /*
61
   * assume the kernel will support openat2(),
62
   * it will be reset on the first ENOSYS.
63
   *
64
   * Note that libreplace will always provide openat2(),
65
   * but return -1/errno = ENOSYS...
66
   *
67
   * The option is only there to test the fallback code.
68
   */
69
0
  bval = lp_parm_bool(SNUM(handle->conn),
70
0
          "vfs_default",
71
0
          "VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS",
72
0
          true);
73
0
  if (bval) {
74
0
    handle->conn->open_how_resolve |=
75
0
      VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
76
0
  }
77
#ifdef DISABLE_VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS
78
  handle->conn->open_how_resolve &= ~VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
79
#endif
80
0
  bval = lp_parm_bool(SNUM(handle->conn),
81
0
          "vfs_default",
82
0
          "VFS_OPEN_HOW_RESOLVE_NO_XDEV",
83
0
          true);
84
0
  if (bval) {
85
0
    handle->conn->open_how_resolve |=
86
0
      VFS_OPEN_HOW_RESOLVE_NO_XDEV;
87
0
  }
88
#ifdef DISABLE_VFS_OPEN_HOW_RESOLVE_NO_XDEV
89
  handle->conn->open_how_resolve &= ~VFS_OPEN_HOW_RESOLVE_NO_XDEV;
90
#endif
91
92
0
  return 0;    /* Return >= 0 for success */
93
0
}
94
95
static void vfswrap_disconnect(vfs_handle_struct *handle)
96
0
{
97
0
}
98
99
/* Disk operations */
100
101
static uint64_t vfswrap_disk_free(vfs_handle_struct *handle,
102
          struct files_struct *fsp,
103
          uint64_t *bsize,
104
          uint64_t *dfree,
105
          uint64_t *dsize)
106
0
{
107
0
  struct vfs_statvfs_struct statvfsbuf;
108
0
  int fd, ret;
109
110
0
  fd = fsp_get_pathref_fd(fsp);
111
112
0
  ret = sys_fstatvfs(fd, &statvfsbuf);
113
0
  if (ret != 0) {
114
0
    return (uint64_t)-1;
115
0
  }
116
0
  statvfs2fsusage(&statvfsbuf, dfree, dsize);
117
118
0
  *bsize = 512;
119
0
  return *dfree / 2;
120
0
}
121
122
static int vfswrap_get_quota(struct vfs_handle_struct *handle,
123
           struct files_struct *fsp,
124
           enum SMB_QUOTA_TYPE qtype,
125
           unid_t id,
126
           SMB_DISK_QUOTA *qt)
127
0
{
128
0
#ifdef HAVE_SYS_QUOTAS
129
0
  struct smb_filename *smb_fname = fsp->fsp_name;
130
0
  int result;
131
132
0
  START_PROFILE_X(SNUM(handle->conn), syscall_get_quota);
133
0
  result = sys_get_quota(
134
0
    smb_fname->st.st_ex_dev, smb_fname->base_name, qtype, id, qt);
135
0
  END_PROFILE_X(syscall_get_quota);
136
0
  return result;
137
#else
138
  errno = ENOSYS;
139
  return -1;
140
#endif
141
0
}
142
143
static int vfswrap_set_quota(struct vfs_handle_struct *handle,
144
           struct files_struct *fsp,
145
           enum SMB_QUOTA_TYPE qtype,
146
           unid_t id,
147
           SMB_DISK_QUOTA *qt)
148
0
{
149
0
#ifdef HAVE_SYS_QUOTAS
150
0
  struct smb_filename *smb_fname = fsp->fsp_name;
151
0
  int result;
152
153
0
  START_PROFILE_X(SNUM(handle->conn), syscall_set_quota);
154
0
  result = sys_set_quota(
155
0
    smb_fname->st.st_ex_dev, smb_fname->base_name, qtype, id, qt);
156
0
  END_PROFILE_X(syscall_set_quota);
157
0
  return result;
158
#else
159
  errno = ENOSYS;
160
  return -1;
161
#endif
162
0
}
163
164
static int vfswrap_get_shadow_copy_data(struct vfs_handle_struct *handle,
165
          struct files_struct *fsp,
166
          struct shadow_copy_data *shadow_copy_data,
167
          bool labels)
168
0
{
169
0
  errno = ENOSYS;
170
0
  return -1;  /* Not implemented. */
171
0
}
172
173
static int vfswrap_fstatvfs(struct vfs_handle_struct *handle,
174
          struct files_struct *fsp,
175
          struct vfs_statvfs_struct *statbuf)
176
0
{
177
0
  int ret, fd;
178
179
0
  START_PROFILE_X(SNUM(handle->conn), syscall_fstatvfs);
180
181
0
  fd = fsp_get_pathref_fd(fsp);
182
183
0
  ret = sys_fstatvfs(fd, statbuf);
184
185
0
  END_PROFILE_X(syscall_fstatvfs);
186
0
  return ret;
187
0
}
188
189
static uint32_t vfswrap_fs_capabilities(struct vfs_handle_struct *handle,
190
    enum timestamp_set_resolution *p_ts_res)
191
0
{
192
0
  uint32_t caps = vfs_get_fs_capabilities(handle->conn, p_ts_res);
193
194
0
#if defined(HAVE_SYS_QUOTAS)
195
0
  caps |= FILE_VOLUME_QUOTAS;
196
0
#endif
197
198
0
  return caps;
199
0
}
200
201
static NTSTATUS vfswrap_get_dfs_referrals(struct vfs_handle_struct *handle,
202
            struct dfs_GetDFSReferral *r)
203
0
{
204
0
  struct junction_map *junction = NULL;
205
0
  size_t consumedcnt = 0;
206
0
  bool self_referral = false;
207
0
  char *pathnamep = NULL;
208
0
  char *local_dfs_path = NULL;
209
0
  NTSTATUS status;
210
0
  size_t i;
211
0
  uint16_t max_referral_level = r->in.req.max_referral_level;
212
213
0
  if (DEBUGLVL(DBGLVL_DEBUG)) {
214
0
    NDR_PRINT_IN_DEBUG(dfs_GetDFSReferral, r);
215
0
  }
216
217
  /* get the junction entry */
218
0
  if (r->in.req.servername == NULL) {
219
0
    return NT_STATUS_NOT_FOUND;
220
0
  }
221
222
  /*
223
   * Trim pathname sent by client so it begins with only one backslash.
224
   * Two backslashes confuse some dfs clients
225
   */
226
227
0
  local_dfs_path = talloc_strdup(r, r->in.req.servername);
228
0
  if (local_dfs_path == NULL) {
229
0
    return NT_STATUS_NO_MEMORY;
230
0
  }
231
0
  pathnamep = local_dfs_path;
232
0
  while (IS_DIRECTORY_SEP(pathnamep[0]) &&
233
0
         IS_DIRECTORY_SEP(pathnamep[1])) {
234
0
    pathnamep++;
235
0
  }
236
237
0
  junction = talloc_zero(r, struct junction_map);
238
0
  if (junction == NULL) {
239
0
    return NT_STATUS_NO_MEMORY;
240
0
  }
241
242
  /* The following call can change cwd. */
243
0
  status = get_referred_path(r,
244
0
           handle->conn->session_info,
245
0
           pathnamep,
246
0
           handle->conn->sconn->remote_address,
247
0
           handle->conn->sconn->local_address,
248
0
           junction, &consumedcnt, &self_referral);
249
0
  vfs_ChDir_shareroot(handle->conn);
250
251
0
  if (!NT_STATUS_IS_OK(status)) {
252
0
    return status;
253
0
  }
254
255
0
  if (!self_referral) {
256
0
    pathnamep[consumedcnt] = '\0';
257
258
0
    if (DEBUGLVL(DBGLVL_INFO)) {
259
0
      dbgtext("Path %s to alternate path(s):",
260
0
        pathnamep);
261
0
      for (i=0; i < junction->referral_count; i++) {
262
0
        dbgtext(" %s",
263
0
        junction->referral_list[i].alternate_path);
264
0
      }
265
0
      dbgtext(".\n");
266
0
    }
267
0
  }
268
269
0
  if (r->in.req.max_referral_level <= 2) {
270
0
    max_referral_level = 2;
271
0
  }
272
0
  if (r->in.req.max_referral_level >= 3) {
273
0
    max_referral_level = 3;
274
0
  }
275
276
0
  r->out.resp = talloc_zero(r, struct dfs_referral_resp);
277
0
  if (r->out.resp == NULL) {
278
0
    return NT_STATUS_NO_MEMORY;
279
0
  }
280
281
0
  r->out.resp->path_consumed = strlen_m(pathnamep) * 2;
282
0
  r->out.resp->nb_referrals = junction->referral_count;
283
284
0
  r->out.resp->header_flags = DFS_HEADER_FLAG_STORAGE_SVR;
285
0
  if (self_referral) {
286
0
    r->out.resp->header_flags |= DFS_HEADER_FLAG_REFERAL_SVR;
287
0
  }
288
289
0
  r->out.resp->referral_entries = talloc_zero_array(r,
290
0
        struct dfs_referral_type,
291
0
        r->out.resp->nb_referrals);
292
0
  if (r->out.resp->referral_entries == NULL) {
293
0
    return NT_STATUS_NO_MEMORY;
294
0
  }
295
296
0
  switch (max_referral_level) {
297
0
  case 2:
298
0
    for(i=0; i < junction->referral_count; i++) {
299
0
      struct referral *ref = &junction->referral_list[i];
300
0
      TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
301
0
      struct dfs_referral_type *t =
302
0
        &r->out.resp->referral_entries[i];
303
0
      struct dfs_referral_v2 *v2 = &t->referral.v2;
304
305
0
      t->version = 2;
306
0
      v2->size = VERSION2_REFERRAL_SIZE;
307
0
      if (self_referral) {
308
0
        v2->server_type = DFS_SERVER_ROOT;
309
0
      } else {
310
0
        v2->server_type = DFS_SERVER_NON_ROOT;
311
0
      }
312
0
      v2->entry_flags = 0;
313
0
      v2->proximity = ref->proximity;
314
0
      v2->ttl = ref->ttl;
315
0
      v2->DFS_path = talloc_strdup(mem_ctx, pathnamep);
316
0
      if (v2->DFS_path == NULL) {
317
0
        return NT_STATUS_NO_MEMORY;
318
0
      }
319
0
      v2->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
320
0
      if (v2->DFS_alt_path == NULL) {
321
0
        return NT_STATUS_NO_MEMORY;
322
0
      }
323
0
      v2->netw_address = talloc_strdup(mem_ctx,
324
0
               ref->alternate_path);
325
0
      if (v2->netw_address == NULL) {
326
0
        return NT_STATUS_NO_MEMORY;
327
0
      }
328
0
    }
329
330
0
    break;
331
0
  case 3:
332
0
    for(i=0; i < junction->referral_count; i++) {
333
0
      struct referral *ref = &junction->referral_list[i];
334
0
      TALLOC_CTX *mem_ctx = r->out.resp->referral_entries;
335
0
      struct dfs_referral_type *t =
336
0
        &r->out.resp->referral_entries[i];
337
0
      struct dfs_referral_v3 *v3 = &t->referral.v3;
338
0
      struct dfs_normal_referral *r1 = &v3->referrals.r1;
339
340
0
      t->version = 3;
341
0
      v3->size = VERSION3_REFERRAL_SIZE;
342
0
      if (self_referral) {
343
0
        v3->server_type = DFS_SERVER_ROOT;
344
0
      } else {
345
0
        v3->server_type = DFS_SERVER_NON_ROOT;
346
0
      }
347
0
      v3->entry_flags = 0;
348
0
      v3->ttl = ref->ttl;
349
0
      r1->DFS_path = talloc_strdup(mem_ctx, pathnamep);
350
0
      if (r1->DFS_path == NULL) {
351
0
        return NT_STATUS_NO_MEMORY;
352
0
      }
353
0
      r1->DFS_alt_path = talloc_strdup(mem_ctx, pathnamep);
354
0
      if (r1->DFS_alt_path == NULL) {
355
0
        return NT_STATUS_NO_MEMORY;
356
0
      }
357
0
      r1->netw_address = talloc_strdup(mem_ctx,
358
0
               ref->alternate_path);
359
0
      if (r1->netw_address == NULL) {
360
0
        return NT_STATUS_NO_MEMORY;
361
0
      }
362
0
    }
363
0
    break;
364
0
  default:
365
0
    DBG_ERR("Invalid dfs referral version: %d\n",
366
0
      max_referral_level);
367
0
    return NT_STATUS_INVALID_LEVEL;
368
0
  }
369
370
0
  if (DEBUGLVL(DBGLVL_DEBUG)) {
371
0
    NDR_PRINT_OUT_DEBUG(dfs_GetDFSReferral, r);
372
0
  }
373
374
0
  return NT_STATUS_OK;
375
0
}
376
377
static NTSTATUS vfswrap_create_dfs_pathat(struct vfs_handle_struct *handle,
378
        struct files_struct *dirfsp,
379
        const struct smb_filename *smb_fname,
380
        const struct referral *reflist,
381
        size_t referral_count)
382
0
{
383
0
  TALLOC_CTX *frame = talloc_stackframe();
384
0
  NTSTATUS status = NT_STATUS_NO_MEMORY;
385
0
  int ret;
386
0
  char *msdfs_link = NULL;
387
388
  /* Form the msdfs_link contents */
389
0
  msdfs_link = msdfs_link_string(frame,
390
0
          reflist,
391
0
          referral_count);
392
0
  if (msdfs_link == NULL) {
393
0
    goto out;
394
0
  }
395
396
0
  ret = symlinkat(msdfs_link,
397
0
      fsp_get_pathref_fd(dirfsp),
398
0
      smb_fname->base_name);
399
0
  if (ret == 0) {
400
0
    status = NT_STATUS_OK;
401
0
  } else {
402
0
    status = map_nt_error_from_unix(errno);
403
0
  }
404
405
0
  out:
406
407
0
  TALLOC_FREE(frame);
408
0
  return status;
409
0
}
410
411
/*
412
 * Read and return the contents of a DFS redirect given a
413
 * pathname. A caller can pass in NULL for ppreflist and
414
 * preferral_count but still determine if this was a
415
 * DFS redirect point by getting NT_STATUS_OK back
416
 * without incurring the overhead of reading and parsing
417
 * the referral contents.
418
 */
419
420
static NTSTATUS vfswrap_read_dfs_pathat(struct vfs_handle_struct *handle,
421
        TALLOC_CTX *mem_ctx,
422
        struct files_struct *dirfsp,
423
        struct smb_filename *smb_fname,
424
        struct referral **ppreflist,
425
        size_t *preferral_count)
426
0
{
427
0
  NTSTATUS status = NT_STATUS_NO_MEMORY;
428
0
  size_t bufsize;
429
0
  char *link_target = NULL;
430
0
  int referral_len;
431
0
  bool ok;
432
#if defined(HAVE_BROKEN_READLINK)
433
  char link_target_buf[PATH_MAX];
434
#else
435
0
  char link_target_buf[7];
436
0
#endif
437
0
  int ret;
438
439
0
  if (is_named_stream(smb_fname)) {
440
0
    status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
441
0
    goto err;
442
0
  }
443
444
0
  if (ppreflist == NULL && preferral_count == NULL) {
445
    /*
446
     * We're only checking if this is a DFS
447
     * redirect. We don't need to return data.
448
     */
449
0
    bufsize = sizeof(link_target_buf);
450
0
    link_target = link_target_buf;
451
0
  } else {
452
0
    bufsize = PATH_MAX;
453
0
    link_target = talloc_array(mem_ctx, char, bufsize);
454
0
    if (!link_target) {
455
0
      goto err;
456
0
    }
457
0
  }
458
459
0
  referral_len = readlinkat(fsp_get_pathref_fd(dirfsp),
460
0
        smb_fname->base_name,
461
0
        link_target,
462
0
        bufsize - 1);
463
0
  if (referral_len == -1) {
464
0
    if (errno == EINVAL) {
465
      /*
466
       * If the path isn't a link, readlinkat
467
       * returns EINVAL. Allow the caller to
468
       * detect this.
469
       */
470
0
      DBG_INFO("%s is not a link.\n", smb_fname->base_name);
471
0
      status = NT_STATUS_OBJECT_TYPE_MISMATCH;
472
0
    } else {
473
0
      status = map_nt_error_from_unix(errno);
474
0
      if (errno == ENOENT) {
475
0
        DBG_NOTICE("Error reading "
476
0
           "msdfs link %s: %s\n",
477
0
           smb_fname->base_name,
478
0
           strerror(errno));
479
0
      } else {
480
0
        DBG_ERR("Error reading "
481
0
          "msdfs link %s: %s\n",
482
0
          smb_fname->base_name,
483
0
          strerror(errno));
484
0
      }
485
0
    }
486
0
                goto err;
487
0
        }
488
0
  link_target[referral_len] = '\0';
489
490
0
  DBG_INFO("%s -> %s\n",
491
0
      smb_fname->base_name,
492
0
      link_target);
493
494
0
  if (!strnequal(link_target, "msdfs:", 6)) {
495
0
    status = NT_STATUS_OBJECT_TYPE_MISMATCH;
496
0
    goto err;
497
0
  }
498
499
0
       ret = sys_fstatat(fsp_get_pathref_fd(dirfsp),
500
0
       smb_fname->base_name,
501
0
       &smb_fname->st,
502
0
       AT_SYMLINK_NOFOLLOW,
503
0
       lp_fake_directory_create_times(SNUM(handle->conn)));
504
0
  if (ret < 0) {
505
0
    status = map_nt_error_from_unix(errno);
506
0
    goto err;
507
0
  }
508
509
0
  if (ppreflist == NULL && preferral_count == NULL) {
510
    /* Early return for checking if this is a DFS link. */
511
0
    return NT_STATUS_OK;
512
0
  }
513
514
0
  ok = parse_msdfs_symlink(mem_ctx,
515
0
      lp_msdfs_shuffle_referrals(SNUM(handle->conn)),
516
0
      link_target,
517
0
      ppreflist,
518
0
      preferral_count);
519
520
0
  if (ok) {
521
0
    status = NT_STATUS_OK;
522
0
  } else {
523
0
    status = NT_STATUS_NO_MEMORY;
524
0
  }
525
526
0
  err:
527
528
0
  if (link_target != link_target_buf) {
529
0
    TALLOC_FREE(link_target);
530
0
  }
531
0
  return status;
532
0
}
533
534
static NTSTATUS vfswrap_snap_check_path(struct vfs_handle_struct *handle,
535
          TALLOC_CTX *mem_ctx,
536
          const char *service_path,
537
          char **base_volume)
538
0
{
539
0
  return NT_STATUS_NOT_SUPPORTED;
540
0
}
541
542
static NTSTATUS vfswrap_snap_create(struct vfs_handle_struct *handle,
543
            TALLOC_CTX *mem_ctx,
544
            const char *base_volume,
545
            time_t *tstamp,
546
            bool rw,
547
            char **base_path,
548
            char **snap_path)
549
0
{
550
0
  return NT_STATUS_NOT_SUPPORTED;
551
0
}
552
553
static NTSTATUS vfswrap_snap_delete(struct vfs_handle_struct *handle,
554
            TALLOC_CTX *mem_ctx,
555
            char *base_path,
556
            char *snap_path)
557
0
{
558
0
  return NT_STATUS_NOT_SUPPORTED;
559
0
}
560
561
/* Directory operations */
562
563
static DIR *vfswrap_fdopendir(vfs_handle_struct *handle,
564
      files_struct *fsp,
565
      const char *mask,
566
      uint32_t attr)
567
0
{
568
0
  DIR *result;
569
570
0
  START_PROFILE_X(SNUM(handle->conn), syscall_fdopendir);
571
0
  result = sys_fdopendir(fsp_get_io_fd(fsp));
572
0
  END_PROFILE_X(syscall_fdopendir);
573
0
  return result;
574
0
}
575
576
static struct dirent *vfswrap_readdir(vfs_handle_struct *handle,
577
              struct files_struct *dirfsp,
578
              DIR *dirp)
579
0
{
580
0
  struct dirent *result;
581
582
0
  START_PROFILE_X(SNUM(handle->conn), syscall_readdir);
583
584
0
  result = readdir(dirp);
585
0
  END_PROFILE_X(syscall_readdir);
586
587
0
  return result;
588
0
}
589
590
static NTSTATUS vfswrap_freaddir_attr(struct vfs_handle_struct *handle,
591
              struct files_struct *fsp,
592
              TALLOC_CTX *mem_ctx,
593
              struct readdir_attr_data **attr_data)
594
0
{
595
0
  return NT_STATUS_NOT_SUPPORTED;
596
0
}
597
598
static void vfswrap_rewinddir(vfs_handle_struct *handle, DIR *dirp)
599
0
{
600
0
  START_PROFILE_X(SNUM(handle->conn), syscall_rewinddir);
601
0
  rewinddir(dirp);
602
0
  END_PROFILE_X(syscall_rewinddir);
603
0
}
604
605
static int vfswrap_mkdirat(vfs_handle_struct *handle,
606
      struct files_struct *dirfsp,
607
      const struct smb_filename *smb_fname,
608
      mode_t mode)
609
0
{
610
0
  int result;
611
612
0
  START_PROFILE_X(SNUM(handle->conn), syscall_mkdirat);
613
614
0
  result = mkdirat(fsp_get_pathref_fd(dirfsp), smb_fname->base_name, mode);
615
616
0
  END_PROFILE_X(syscall_mkdirat);
617
0
  return result;
618
0
}
619
620
static int vfswrap_closedir(vfs_handle_struct *handle, DIR *dirp)
621
0
{
622
0
  int result;
623
624
0
  START_PROFILE_X(SNUM(handle->conn), syscall_closedir);
625
0
  result = closedir(dirp);
626
0
  END_PROFILE_X(syscall_closedir);
627
0
  return result;
628
0
}
629
630
/* File operations */
631
632
static int vfswrap_openat(vfs_handle_struct *handle,
633
        const struct files_struct *dirfsp,
634
        const struct smb_filename *smb_fname,
635
        files_struct *fsp,
636
        const struct vfs_open_how *how)
637
0
{
638
0
  int dirfd = fsp_get_pathref_fd(dirfsp);
639
0
  int flags = how->flags;
640
0
  mode_t mode = how->mode;
641
0
  bool have_opath = false;
642
0
  bool became_root = false;
643
0
  int result;
644
645
0
  START_PROFILE_X(SNUM(handle->conn), syscall_openat);
646
647
0
  SMB_ASSERT((dirfd != -1) || (smb_fname->base_name[0] == '/'));
648
649
0
  if (how->resolve & ~(VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS |
650
0
           VFS_OPEN_HOW_WITH_BACKUP_INTENT |
651
0
           VFS_OPEN_HOW_RESOLVE_NO_XDEV))
652
0
  {
653
0
    errno = ENOSYS;
654
0
    result = -1;
655
0
    goto out;
656
0
  }
657
658
0
  SMB_ASSERT(!is_named_stream(smb_fname));
659
660
0
#ifdef O_PATH
661
0
  have_opath = true;
662
0
  if (fsp->fsp_flags.is_pathref) {
663
0
    flags |= O_PATH;
664
0
  }
665
0
  if (flags & O_PATH) {
666
    /*
667
     * From "man 2 openat":
668
     *
669
     *   When O_PATH is specified in flags, flag bits other than
670
     *   O_CLOEXEC, O_DIRECTORY, and O_NOFOLLOW are ignored.
671
     *
672
     * From "man 2 openat2":
673
     *
674
     *   Whereas  openat(2)  ignores  unknown  bits  in  its  flags
675
     *   argument, openat2() returns an error if unknown or
676
     *   conflicting flags are specified in how.flags.
677
     *
678
     * So we better clear ignored/invalid flags
679
     * and only keep the expected ones.
680
     */
681
0
    flags &= (O_PATH|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
682
0
  }
683
0
#endif
684
685
0
  if (how->resolve & VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS ||
686
0
      how->resolve & VFS_OPEN_HOW_RESOLVE_NO_XDEV)
687
0
  {
688
0
    struct open_how linux_how = {
689
0
      .flags = flags,
690
0
      .mode = mode,
691
0
      .resolve = 0,
692
0
    };
693
0
    if (how->resolve & VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS) {
694
0
      linux_how.resolve |= RESOLVE_NO_SYMLINKS;
695
0
    }
696
0
    if (how->resolve & VFS_OPEN_HOW_RESOLVE_NO_XDEV) {
697
0
      linux_how.resolve |= RESOLVE_NO_XDEV;
698
0
    }
699
700
0
    result = openat2(dirfd,
701
0
         smb_fname->base_name,
702
0
         &linux_how,
703
0
         sizeof(linux_how));
704
0
    if (result == -1) {
705
0
      if (errno == ENOSYS) {
706
        /*
707
         * The kernel doesn't support
708
         * openat2(), so indicate to
709
         * the callers that
710
         * VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS
711
         * or VFS_OPEN_HOW_RESOLVE_NO_XDEV
712
         * would just be a waste of time.
713
         */
714
0
        fsp->conn->open_how_resolve &=
715
0
          ~VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
716
0
        fsp->conn->open_how_resolve &=
717
0
          ~VFS_OPEN_HOW_RESOLVE_NO_XDEV;
718
0
      }
719
0
      goto out;
720
0
    }
721
722
0
    goto done;
723
0
  }
724
725
0
  if (fsp->fsp_flags.is_pathref && !have_opath) {
726
0
    become_root();
727
0
    became_root = true;
728
0
  }
729
730
0
  result = openat(dirfd,
731
0
      smb_fname->base_name,
732
0
      flags,
733
0
      mode);
734
735
0
  if (became_root) {
736
0
    int err = errno;
737
0
    unbecome_root();
738
0
    errno = err;
739
0
  }
740
741
0
done:
742
0
  if (result >= 0) {
743
0
    fsp->fsp_flags.have_proc_fds = fsp->conn->have_proc_fds;
744
0
  } else {
745
    /*
746
     * "/proc/self/fd/-1" never exists. Indicate to upper
747
     * layers that for this fsp a possible name-based
748
     * fallback is the only way to go.
749
     */
750
0
    fsp->fsp_flags.have_proc_fds = false;
751
0
  }
752
753
0
out:
754
0
  END_PROFILE_X(syscall_openat);
755
0
  return result;
756
0
}
757
static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle,
758
            struct smb_request *req,
759
            struct files_struct *dirfsp,
760
            struct smb_filename *smb_fname,
761
            uint32_t access_mask,
762
            uint32_t share_access,
763
            uint32_t create_disposition,
764
            uint32_t create_options,
765
            uint32_t file_attributes,
766
            uint32_t oplock_request,
767
            const struct smb2_lease *lease,
768
            uint64_t allocation_size,
769
            uint32_t private_flags,
770
            struct security_descriptor *sd,
771
            struct ea_list *ea_list,
772
            files_struct **result,
773
            int *pinfo,
774
            const struct smb2_create_blobs *in_context_blobs,
775
            struct smb2_create_blobs *out_context_blobs)
776
0
{
777
0
  return create_file_default(handle->conn, req, dirfsp, smb_fname,
778
0
           access_mask, share_access,
779
0
           create_disposition, create_options,
780
0
           file_attributes, oplock_request, lease,
781
0
           allocation_size, private_flags,
782
0
           sd, ea_list, result,
783
0
           pinfo, in_context_blobs, out_context_blobs);
784
0
}
785
786
static int vfswrap_close(vfs_handle_struct *handle, files_struct *fsp)
787
0
{
788
0
  int result;
789
790
0
  START_PROFILE_X(SNUM(handle->conn), syscall_close);
791
0
  result = fd_close_posix(fsp);
792
0
  END_PROFILE_X(syscall_close);
793
0
  return result;
794
0
}
795
796
static ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, void *data,
797
      size_t n, off_t offset)
798
0
{
799
0
  ssize_t result;
800
801
0
#if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
802
0
  START_PROFILE_BYTES_X(SNUM(handle->conn), syscall_pread, n);
803
0
  result = sys_pread_full(fsp_get_io_fd(fsp), data, n, offset);
804
0
  END_PROFILE_BYTES_X(syscall_pread);
805
806
0
  if (result == -1 && errno == ESPIPE) {
807
    /* Maintain the fiction that pipes can be seeked (sought?) on. */
808
0
    result = sys_read(fsp_get_io_fd(fsp), data, n);
809
0
    fh_set_pos(fsp->fh, 0);
810
0
  }
811
812
#else /* HAVE_PREAD */
813
  errno = ENOSYS;
814
  result = -1;
815
#endif /* HAVE_PREAD */
816
817
0
  return result;
818
0
}
819
820
static ssize_t vfswrap_pwrite(vfs_handle_struct *handle, files_struct *fsp, const void *data,
821
      size_t n, off_t offset)
822
0
{
823
0
  ssize_t result;
824
825
0
#if defined(HAVE_PWRITE) || defined(HAVE_PRWITE64)
826
0
  START_PROFILE_BYTES_X(SNUM(handle->conn), syscall_pwrite, n);
827
828
0
  if (fsp->fsp_flags.posix_append) {
829
0
    SMB_ASSERT(offset == VFS_PWRITE_APPEND_OFFSET);
830
0
  } else {
831
0
    SMB_ASSERT(offset >= 0);
832
0
  }
833
834
0
  if (fsp->fsp_flags.posix_append) {
835
0
    result = sys_write_full(fsp_get_io_fd(fsp), data, n);
836
0
  } else {
837
0
    result = sys_pwrite_full(fsp_get_io_fd(fsp), data, n, offset);
838
0
  }
839
0
  END_PROFILE_BYTES_X(syscall_pwrite);
840
841
0
  if (result == -1 && errno == ESPIPE) {
842
    /* Maintain the fiction that pipes can be sought on. */
843
0
    result = sys_write(fsp_get_io_fd(fsp), data, n);
844
0
  }
845
846
#else /* HAVE_PWRITE */
847
  errno = ENOSYS;
848
  result = -1;
849
#endif /* HAVE_PWRITE */
850
851
0
  return result;
852
0
}
853
854
struct vfswrap_pread_state {
855
  ssize_t ret;
856
  int fd;
857
  void *buf;
858
  size_t count;
859
  off_t offset;
860
861
  struct vfs_aio_state vfs_aio_state;
862
  SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
863
  SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes_x);
864
};
865
866
static void vfs_pread_do(void *private_data);
867
static void vfs_pread_done(struct tevent_req *subreq);
868
static int vfs_pread_state_destructor(struct vfswrap_pread_state *state);
869
870
static struct tevent_req *vfswrap_pread_send(struct vfs_handle_struct *handle,
871
               TALLOC_CTX *mem_ctx,
872
               struct tevent_context *ev,
873
               struct files_struct *fsp,
874
               void *data,
875
               size_t n, off_t offset)
876
0
{
877
0
  struct tevent_req *req, *subreq;
878
0
  struct vfswrap_pread_state *state;
879
880
0
  req = tevent_req_create(mem_ctx, &state, struct vfswrap_pread_state);
881
0
  if (req == NULL) {
882
0
    return NULL;
883
0
  }
884
885
0
  state->ret = -1;
886
0
  state->fd = fsp_get_io_fd(fsp);
887
0
  state->buf = data;
888
0
  state->count = n;
889
0
  state->offset = offset;
890
891
0
  SMBPROFILE_BYTES_ASYNC_START_X(SNUM(handle->conn),
892
0
               syscall_asys_pread,
893
0
               state->profile_bytes,
894
0
               state->profile_bytes_x,
895
0
               n);
896
0
  SMBPROFILE_BYTES_ASYNC_SET_IDLE_X(state->profile_bytes,
897
0
            state->profile_bytes_x);
898
899
0
  subreq = pthreadpool_tevent_job_send(
900
0
    state, ev, handle->conn->sconn->pool,
901
0
    vfs_pread_do, state);
902
0
  if (tevent_req_nomem(subreq, req)) {
903
0
    return tevent_req_post(req, ev);
904
0
  }
905
0
  tevent_req_set_callback(subreq, vfs_pread_done, req);
906
907
0
  talloc_set_destructor(state, vfs_pread_state_destructor);
908
909
0
  return req;
910
0
}
911
912
static void vfs_pread_do(void *private_data)
913
0
{
914
0
  struct vfswrap_pread_state *state = talloc_get_type_abort(
915
0
    private_data, struct vfswrap_pread_state);
916
0
  struct timespec start_time;
917
0
  struct timespec end_time;
918
919
0
  SMBPROFILE_BYTES_ASYNC_SET_BUSY_X(state->profile_bytes,
920
0
            state->profile_bytes_x);
921
922
0
  PROFILE_TIMESTAMP(&start_time);
923
924
0
  state->ret = sys_pread_full(state->fd,
925
0
            state->buf,
926
0
            state->count,
927
0
            state->offset);
928
929
0
  if (state->ret == -1) {
930
0
    state->vfs_aio_state.error = errno;
931
0
  }
932
933
0
  PROFILE_TIMESTAMP(&end_time);
934
935
0
  state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
936
937
0
  SMBPROFILE_BYTES_ASYNC_SET_IDLE_X(state->profile_bytes,
938
0
            state->profile_bytes_x);
939
0
}
940
941
static int vfs_pread_state_destructor(struct vfswrap_pread_state *state)
942
0
{
943
0
  return -1;
944
0
}
945
946
static void vfs_pread_done(struct tevent_req *subreq)
947
0
{
948
0
  struct tevent_req *req = tevent_req_callback_data(
949
0
    subreq, struct tevent_req);
950
0
  struct vfswrap_pread_state *state = tevent_req_data(
951
0
    req, struct vfswrap_pread_state);
952
0
  int ret;
953
954
0
  ret = pthreadpool_tevent_job_recv(subreq);
955
0
  TALLOC_FREE(subreq);
956
0
  SMBPROFILE_BYTES_ASYNC_END_X(state->profile_bytes,
957
0
             state->profile_bytes_x);
958
0
  talloc_set_destructor(state, NULL);
959
0
  if (ret != 0) {
960
0
    if (ret != EAGAIN) {
961
0
      tevent_req_error(req, ret);
962
0
      return;
963
0
    }
964
    /*
965
     * If we get EAGAIN from pthreadpool_tevent_job_recv() this
966
     * means the lower level pthreadpool failed to create a new
967
     * thread. Fallback to sync processing in that case to allow
968
     * some progress for the client.
969
     */
970
0
    vfs_pread_do(state);
971
0
  }
972
973
0
  tevent_req_done(req);
974
0
}
975
976
static ssize_t vfswrap_pread_recv(struct tevent_req *req,
977
          struct vfs_aio_state *vfs_aio_state)
978
0
{
979
0
  struct vfswrap_pread_state *state = tevent_req_data(
980
0
    req, struct vfswrap_pread_state);
981
982
0
  if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
983
0
    return -1;
984
0
  }
985
986
0
  *vfs_aio_state = state->vfs_aio_state;
987
0
  return state->ret;
988
0
}
989
990
struct vfswrap_pwrite_state {
991
  ssize_t ret;
992
  int fd;
993
  const void *buf;
994
  size_t count;
995
  off_t offset;
996
  bool posix_append;
997
998
  struct vfs_aio_state vfs_aio_state;
999
  SMBPROFILE_BYTES_ASYNC_STATE_X(profile_bytes, profile_bytes_x);
1000
};
1001
1002
static void vfs_pwrite_do(void *private_data);
1003
static void vfs_pwrite_done(struct tevent_req *subreq);
1004
static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state);
1005
1006
static struct tevent_req *vfswrap_pwrite_send(struct vfs_handle_struct *handle,
1007
                TALLOC_CTX *mem_ctx,
1008
                struct tevent_context *ev,
1009
                struct files_struct *fsp,
1010
                const void *data,
1011
                size_t n, off_t offset)
1012
0
{
1013
0
  struct tevent_req *req, *subreq;
1014
0
  struct vfswrap_pwrite_state *state;
1015
1016
0
  req = tevent_req_create(mem_ctx, &state, struct vfswrap_pwrite_state);
1017
0
  if (req == NULL) {
1018
0
    return NULL;
1019
0
  }
1020
1021
0
  state->ret = -1;
1022
0
  state->fd = fsp_get_io_fd(fsp);
1023
0
  state->buf = data;
1024
0
  state->count = n;
1025
0
  state->offset = offset;
1026
1027
0
  if (fsp->fsp_flags.posix_append) {
1028
0
    SMB_ASSERT(state->offset == VFS_PWRITE_APPEND_OFFSET);
1029
0
    state->posix_append = true;
1030
0
  } else {
1031
0
    SMB_ASSERT(state->offset >= 0);
1032
0
  }
1033
1034
0
  SMBPROFILE_BYTES_ASYNC_START_X(SNUM(handle->conn),
1035
0
               syscall_asys_pwrite,
1036
0
               state->profile_bytes,
1037
0
               state->profile_bytes_x,
1038
0
               n);
1039
0
  SMBPROFILE_BYTES_ASYNC_SET_IDLE_X(state->profile_bytes,
1040
0
            state->profile_bytes_x);
1041
1042
0
  subreq = pthreadpool_tevent_job_send(
1043
0
    state, ev, handle->conn->sconn->pool,
1044
0
    vfs_pwrite_do, state);
1045
0
  if (tevent_req_nomem(subreq, req)) {
1046
0
    return tevent_req_post(req, ev);
1047
0
  }
1048
0
  tevent_req_set_callback(subreq, vfs_pwrite_done, req);
1049
1050
0
  talloc_set_destructor(state, vfs_pwrite_state_destructor);
1051
1052
0
  return req;
1053
0
}
1054
1055
static void vfs_pwrite_do(void *private_data)
1056
0
{
1057
0
  struct vfswrap_pwrite_state *state = talloc_get_type_abort(
1058
0
    private_data, struct vfswrap_pwrite_state);
1059
0
  struct timespec start_time;
1060
0
  struct timespec end_time;
1061
1062
0
  SMBPROFILE_BYTES_ASYNC_SET_BUSY_X(state->profile_bytes,
1063
0
            state->profile_bytes_x);
1064
1065
0
  PROFILE_TIMESTAMP(&start_time);
1066
1067
0
  if (state->posix_append) {
1068
0
    state->ret = sys_write_full(state->fd,
1069
0
              state->buf,
1070
0
              state->count);
1071
0
  } else {
1072
0
    state->ret = sys_pwrite_full(state->fd,
1073
0
               state->buf,
1074
0
               state->count,
1075
0
               state->offset);
1076
0
  }
1077
1078
0
  if (state->ret == -1) {
1079
0
    state->vfs_aio_state.error = errno;
1080
0
  }
1081
1082
0
  PROFILE_TIMESTAMP(&end_time);
1083
1084
0
  state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1085
1086
0
  SMBPROFILE_BYTES_ASYNC_SET_IDLE_X(state->profile_bytes,
1087
0
            state->profile_bytes_x);
1088
0
}
1089
1090
static int vfs_pwrite_state_destructor(struct vfswrap_pwrite_state *state)
1091
0
{
1092
0
  return -1;
1093
0
}
1094
1095
static void vfs_pwrite_done(struct tevent_req *subreq)
1096
0
{
1097
0
  struct tevent_req *req = tevent_req_callback_data(
1098
0
    subreq, struct tevent_req);
1099
0
  struct vfswrap_pwrite_state *state = tevent_req_data(
1100
0
    req, struct vfswrap_pwrite_state);
1101
0
  int ret;
1102
1103
0
  ret = pthreadpool_tevent_job_recv(subreq);
1104
0
  TALLOC_FREE(subreq);
1105
0
  SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1106
0
  SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes_x);
1107
0
  talloc_set_destructor(state, NULL);
1108
0
  if (ret != 0) {
1109
0
    if (ret != EAGAIN) {
1110
0
      tevent_req_error(req, ret);
1111
0
      return;
1112
0
    }
1113
    /*
1114
     * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1115
     * means the lower level pthreadpool failed to create a new
1116
     * thread. Fallback to sync processing in that case to allow
1117
     * some progress for the client.
1118
     */
1119
0
    vfs_pwrite_do(state);
1120
0
  }
1121
1122
0
  tevent_req_done(req);
1123
0
}
1124
1125
static ssize_t vfswrap_pwrite_recv(struct tevent_req *req,
1126
           struct vfs_aio_state *vfs_aio_state)
1127
0
{
1128
0
  struct vfswrap_pwrite_state *state = tevent_req_data(
1129
0
    req, struct vfswrap_pwrite_state);
1130
1131
0
  if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1132
0
    return -1;
1133
0
  }
1134
1135
0
  *vfs_aio_state = state->vfs_aio_state;
1136
0
  return state->ret;
1137
0
}
1138
1139
struct vfswrap_fsync_state {
1140
  ssize_t ret;
1141
  int fd;
1142
1143
  struct vfs_aio_state vfs_aio_state;
1144
  SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
1145
  SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes_x);
1146
};
1147
1148
static void vfs_fsync_do(void *private_data);
1149
static void vfs_fsync_done(struct tevent_req *subreq);
1150
static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state);
1151
1152
static struct tevent_req *vfswrap_fsync_send(struct vfs_handle_struct *handle,
1153
               TALLOC_CTX *mem_ctx,
1154
               struct tevent_context *ev,
1155
               struct files_struct *fsp)
1156
0
{
1157
0
  struct tevent_req *req, *subreq;
1158
0
  struct vfswrap_fsync_state *state;
1159
1160
0
  req = tevent_req_create(mem_ctx, &state, struct vfswrap_fsync_state);
1161
0
  if (req == NULL) {
1162
0
    return NULL;
1163
0
  }
1164
1165
0
  state->ret = -1;
1166
0
  state->fd = fsp_get_io_fd(fsp);
1167
1168
0
  SMBPROFILE_BYTES_ASYNC_START_X(SNUM(handle->conn),
1169
0
               syscall_asys_fsync,
1170
0
               state->profile_bytes,
1171
0
               state->profile_bytes_x,
1172
0
               0);
1173
0
  SMBPROFILE_BYTES_ASYNC_SET_IDLE_X(state->profile_bytes,
1174
0
            state->profile_bytes_x);
1175
1176
0
  subreq = pthreadpool_tevent_job_send(
1177
0
    state, ev, handle->conn->sconn->pool, vfs_fsync_do, state);
1178
0
  if (tevent_req_nomem(subreq, req)) {
1179
0
    return tevent_req_post(req, ev);
1180
0
  }
1181
0
  tevent_req_set_callback(subreq, vfs_fsync_done, req);
1182
1183
0
  talloc_set_destructor(state, vfs_fsync_state_destructor);
1184
1185
0
  return req;
1186
0
}
1187
1188
static void vfs_fsync_do(void *private_data)
1189
0
{
1190
0
  struct vfswrap_fsync_state *state = talloc_get_type_abort(
1191
0
    private_data, struct vfswrap_fsync_state);
1192
0
  struct timespec start_time;
1193
0
  struct timespec end_time;
1194
1195
0
  SMBPROFILE_BYTES_ASYNC_SET_BUSY_X(state->profile_bytes,
1196
0
            state->profile_bytes_x);
1197
1198
0
  PROFILE_TIMESTAMP(&start_time);
1199
1200
0
  do {
1201
0
    state->ret = fsync(state->fd);
1202
0
  } while ((state->ret == -1) && (errno == EINTR));
1203
1204
0
  if (state->ret == -1) {
1205
0
    state->vfs_aio_state.error = errno;
1206
0
  }
1207
1208
0
  PROFILE_TIMESTAMP(&end_time);
1209
1210
0
  state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1211
1212
0
  SMBPROFILE_BYTES_ASYNC_SET_IDLE_X(state->profile_bytes,
1213
0
            state->profile_bytes_x);
1214
0
}
1215
1216
static int vfs_fsync_state_destructor(struct vfswrap_fsync_state *state)
1217
0
{
1218
0
  return -1;
1219
0
}
1220
1221
static void vfs_fsync_done(struct tevent_req *subreq)
1222
0
{
1223
0
  struct tevent_req *req = tevent_req_callback_data(
1224
0
    subreq, struct tevent_req);
1225
0
  struct vfswrap_fsync_state *state = tevent_req_data(
1226
0
    req, struct vfswrap_fsync_state);
1227
0
  int ret;
1228
1229
0
  ret = pthreadpool_tevent_job_recv(subreq);
1230
0
  TALLOC_FREE(subreq);
1231
0
  SMBPROFILE_BYTES_ASYNC_END_X(state->profile_bytes,
1232
0
             state->profile_bytes_x);
1233
0
  talloc_set_destructor(state, NULL);
1234
0
  if (ret != 0) {
1235
0
    if (ret != EAGAIN) {
1236
0
      tevent_req_error(req, ret);
1237
0
      return;
1238
0
    }
1239
    /*
1240
     * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1241
     * means the lower level pthreadpool failed to create a new
1242
     * thread. Fallback to sync processing in that case to allow
1243
     * some progress for the client.
1244
     */
1245
0
    vfs_fsync_do(state);
1246
0
  }
1247
1248
0
  tevent_req_done(req);
1249
0
}
1250
1251
static int vfswrap_fsync_recv(struct tevent_req *req,
1252
            struct vfs_aio_state *vfs_aio_state)
1253
0
{
1254
0
  struct vfswrap_fsync_state *state = tevent_req_data(
1255
0
    req, struct vfswrap_fsync_state);
1256
1257
0
  if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1258
0
    return -1;
1259
0
  }
1260
1261
0
  *vfs_aio_state = state->vfs_aio_state;
1262
0
  return state->ret;
1263
0
}
1264
1265
static off_t vfswrap_lseek(vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
1266
0
{
1267
0
  off_t result = 0;
1268
1269
0
  START_PROFILE_X(SNUM(handle->conn), syscall_lseek);
1270
1271
0
  result = lseek(fsp_get_io_fd(fsp), offset, whence);
1272
  /*
1273
   * We want to maintain the fiction that we can seek
1274
   * on a fifo for file system purposes. This allows
1275
   * people to set up UNIX fifo's that feed data to Windows
1276
   * applications. JRA.
1277
   */
1278
1279
0
  if((result == -1) && (errno == ESPIPE)) {
1280
0
    result = 0;
1281
0
    errno = 0;
1282
0
  }
1283
1284
0
  END_PROFILE_X(syscall_lseek);
1285
0
  return result;
1286
0
}
1287
1288
static ssize_t vfswrap_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
1289
      off_t offset, size_t n)
1290
0
{
1291
0
  ssize_t result;
1292
1293
0
  START_PROFILE_BYTES_X(SNUM(handle->conn), syscall_sendfile, n);
1294
0
  result = sys_sendfile(tofd, fsp_get_io_fd(fromfsp), hdr, offset, n);
1295
0
  END_PROFILE_BYTES_X(syscall_sendfile);
1296
0
  return result;
1297
0
}
1298
1299
static ssize_t vfswrap_recvfile(vfs_handle_struct *handle,
1300
      int fromfd,
1301
      files_struct *tofsp,
1302
      off_t offset,
1303
      size_t n)
1304
0
{
1305
0
  ssize_t result;
1306
1307
0
  START_PROFILE_BYTES_X(SNUM(handle->conn), syscall_recvfile, n);
1308
0
  result = sys_recvfile(fromfd, fsp_get_io_fd(tofsp), offset, n);
1309
0
  END_PROFILE_BYTES_X(syscall_recvfile);
1310
0
  return result;
1311
0
}
1312
1313
static int vfswrap_renameat(vfs_handle_struct *handle,
1314
          files_struct *src_dirfsp,
1315
          const struct smb_filename *smb_fname_src,
1316
          files_struct *dst_dirfsp,
1317
          const struct smb_filename *smb_fname_dst,
1318
          const struct vfs_rename_how *how)
1319
0
{
1320
0
  int result = -1;
1321
0
  int flags = 0;
1322
1323
0
  START_PROFILE_X(SNUM(handle->conn), syscall_renameat);
1324
1325
0
  SMB_ASSERT(!is_named_stream(smb_fname_src));
1326
0
  SMB_ASSERT(!is_named_stream(smb_fname_dst));
1327
1328
0
  if (how->flags & ~VFS_RENAME_HOW_NO_REPLACE) {
1329
0
    END_PROFILE_X(syscall_renameat);
1330
0
    errno = EINVAL;
1331
0
    return -1;
1332
0
  }
1333
1334
0
  if (how->flags & VFS_RENAME_HOW_NO_REPLACE) {
1335
0
    flags |= RENAME_NOREPLACE;
1336
0
  }
1337
1338
0
  result = renameat2(fsp_get_pathref_fd(src_dirfsp),
1339
0
         smb_fname_src->base_name,
1340
0
         fsp_get_pathref_fd(dst_dirfsp),
1341
0
         smb_fname_dst->base_name,
1342
0
         flags);
1343
1344
0
  END_PROFILE_X(syscall_renameat);
1345
0
  return result;
1346
0
}
1347
1348
static int vfswrap_rename_stream(struct vfs_handle_struct *handle,
1349
         struct files_struct *src_fsp,
1350
         const char *dst_name,
1351
         bool replace_if_exists)
1352
0
{
1353
0
  int result = -1;
1354
0
  START_PROFILE_X(SNUM(handle->conn), syscall_rename_stream);
1355
0
  errno = ENOSYS;
1356
0
  END_PROFILE_X(syscall_rename_stream);
1357
0
  return result;
1358
0
}
1359
1360
static int vfswrap_stat(vfs_handle_struct *handle,
1361
      struct smb_filename *smb_fname)
1362
0
{
1363
0
  int result = -1;
1364
1365
0
  START_PROFILE_X(SNUM(handle->conn), syscall_stat);
1366
1367
0
  SMB_ASSERT(!is_named_stream(smb_fname));
1368
1369
0
  result = sys_stat(smb_fname->base_name, &smb_fname->st,
1370
0
        lp_fake_directory_create_times(SNUM(handle->conn)));
1371
1372
0
  END_PROFILE_X(syscall_stat);
1373
0
  return result;
1374
0
}
1375
1376
static int vfswrap_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1377
0
{
1378
0
  int result;
1379
1380
0
  START_PROFILE_X(SNUM(handle->conn), syscall_fstat);
1381
0
  result = sys_fstat(fsp_get_pathref_fd(fsp),
1382
0
         sbuf, lp_fake_directory_create_times(SNUM(handle->conn)));
1383
0
  END_PROFILE_X(syscall_fstat);
1384
0
  return result;
1385
0
}
1386
1387
static int vfswrap_lstat(vfs_handle_struct *handle,
1388
       struct smb_filename *smb_fname)
1389
0
{
1390
0
  int result = -1;
1391
1392
0
  START_PROFILE_X(SNUM(handle->conn), syscall_lstat);
1393
1394
0
  SMB_ASSERT(!is_named_stream(smb_fname));
1395
1396
0
  result = sys_lstat(smb_fname->base_name, &smb_fname->st,
1397
0
         lp_fake_directory_create_times(SNUM(handle->conn)));
1398
1399
0
  END_PROFILE_X(syscall_lstat);
1400
0
  return result;
1401
0
}
1402
1403
static int vfswrap_fstatat(
1404
  struct vfs_handle_struct *handle,
1405
  const struct files_struct *dirfsp,
1406
  const struct smb_filename *smb_fname,
1407
  SMB_STRUCT_STAT *sbuf,
1408
  int flags)
1409
0
{
1410
0
  int result = -1;
1411
1412
0
  START_PROFILE_X(SNUM(handle->conn), syscall_fstatat);
1413
1414
0
  SMB_ASSERT(!is_named_stream(smb_fname));
1415
1416
0
  result = sys_fstatat(
1417
0
    fsp_get_pathref_fd(dirfsp),
1418
0
    smb_fname->base_name,
1419
0
    sbuf,
1420
0
    flags,
1421
0
    lp_fake_directory_create_times(SNUM(handle->conn)));
1422
1423
0
  END_PROFILE_X(syscall_fstatat);
1424
0
  return result;
1425
0
}
1426
1427
static NTSTATUS vfswrap_translate_name(struct vfs_handle_struct *handle,
1428
               const char *name,
1429
               enum vfs_translate_direction direction,
1430
               TALLOC_CTX *mem_ctx,
1431
               char **mapped_name)
1432
0
{
1433
0
  return NT_STATUS_NONE_MAPPED;
1434
0
}
1435
1436
/**
1437
 * Return allocated parent directory and basename of path
1438
 *
1439
 * Note: if requesting atname, it is returned as talloc child of the
1440
 * parent. Freeing the parent is thus sufficient to free both.
1441
 */
1442
static NTSTATUS vfswrap_parent_pathname(struct vfs_handle_struct *handle,
1443
          TALLOC_CTX *mem_ctx,
1444
          const struct smb_filename *smb_fname_in,
1445
          struct smb_filename **parent_dir_out,
1446
          struct smb_filename **atname_out)
1447
0
{
1448
0
  struct smb_filename *parent = NULL;
1449
0
  struct smb_filename *name = NULL;
1450
0
  char *p = NULL;
1451
1452
0
  parent = cp_smb_filename_nostream(mem_ctx, smb_fname_in);
1453
0
  if (parent == NULL) {
1454
0
    return NT_STATUS_NO_MEMORY;
1455
0
  }
1456
0
  SET_STAT_INVALID(parent->st);
1457
1458
0
  p = strrchr_m(parent->base_name, '/'); /* Find final '/', if any */
1459
0
  if (p == NULL) {
1460
0
    TALLOC_FREE(parent->base_name);
1461
0
    parent->base_name = talloc_strdup(parent, ".");
1462
0
    if (parent->base_name == NULL) {
1463
0
      TALLOC_FREE(parent);
1464
0
      return NT_STATUS_NO_MEMORY;
1465
0
    }
1466
0
    p = smb_fname_in->base_name;
1467
0
  } else {
1468
0
    *p = '\0';
1469
0
    p++;
1470
0
  }
1471
1472
0
  if (atname_out == NULL) {
1473
0
    *parent_dir_out = parent;
1474
0
    return NT_STATUS_OK;
1475
0
  }
1476
1477
0
  name = synthetic_smb_fname(
1478
0
    parent,
1479
0
    p,
1480
0
    smb_fname_in->stream_name,
1481
0
    &smb_fname_in->st,
1482
0
    smb_fname_in->twrp,
1483
0
    smb_fname_in->flags);
1484
0
  if (name == NULL) {
1485
0
    TALLOC_FREE(parent);
1486
0
    return NT_STATUS_NO_MEMORY;
1487
0
  }
1488
1489
0
  *parent_dir_out = parent;
1490
0
  *atname_out = name;
1491
0
  return NT_STATUS_OK;
1492
0
}
1493
1494
/*
1495
 * Implement the default fsctl operation.
1496
 */
1497
static bool vfswrap_logged_ioctl_message = false;
1498
1499
static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
1500
            struct files_struct *fsp,
1501
            TALLOC_CTX *ctx,
1502
            uint32_t function,
1503
            uint16_t req_flags, /* Needed for UNICODE ... */
1504
            const uint8_t *_in_data,
1505
            uint32_t in_len,
1506
            uint8_t **_out_data,
1507
            uint32_t max_out_len,
1508
            uint32_t *out_len)
1509
0
{
1510
0
  const char *in_data = (const char *)_in_data;
1511
0
  char **out_data = (char **)_out_data;
1512
0
  NTSTATUS status;
1513
1514
  /*
1515
   * Currently all fsctls operate on the base
1516
   * file if given an alternate data stream.
1517
   * Revisit this if we implement fsctls later
1518
   * that need access to the ADS handle.
1519
   */
1520
0
  fsp = metadata_fsp(fsp);
1521
1522
0
  switch (function) {
1523
0
  case FSCTL_SET_SPARSE:
1524
0
  {
1525
0
    bool set_sparse = true;
1526
1527
0
    if (in_len >= 1 && in_data[0] == 0) {
1528
0
      set_sparse = false;
1529
0
    }
1530
1531
0
    status = file_set_sparse(handle->conn, fsp, set_sparse);
1532
1533
0
    DEBUG(NT_STATUS_IS_OK(status) ? 10 : 9,
1534
0
          ("FSCTL_SET_SPARSE: fname[%s] set[%u] - %s\n",
1535
0
           smb_fname_str_dbg(fsp->fsp_name), set_sparse,
1536
0
           nt_errstr(status)));
1537
1538
0
    return status;
1539
0
  }
1540
1541
0
  case FSCTL_CREATE_OR_GET_OBJECT_ID:
1542
0
  {
1543
0
    unsigned char objid[16];
1544
0
    uint8_t *return_data = NULL;
1545
1546
    /* This should return the object-id on this file.
1547
     * I think I'll make this be the inode+dev. JRA.
1548
     */
1549
1550
0
    DBG_DEBUG("FSCTL_CREATE_OR_GET_OBJECT_ID: called on %s\n",
1551
0
        fsp_fnum_dbg(fsp));
1552
1553
0
    *out_len = MIN(max_out_len, 64);
1554
1555
    /* Hmmm, will this cause problems if less data asked for? */
1556
0
    return_data = talloc_array(ctx, uint8_t, 64);
1557
0
    if (return_data == NULL) {
1558
0
      return NT_STATUS_NO_MEMORY;
1559
0
    }
1560
1561
    /* For backwards compatibility only store the dev/inode. */
1562
0
    push_file_id_16(return_data, &fsp->file_id);
1563
0
    memcpy(return_data+16,create_volume_objectid(fsp->conn,objid),16);
1564
0
    push_file_id_16(return_data + 32, &fsp->file_id);
1565
0
    memset(return_data+48, 0, 16);
1566
0
    *_out_data = return_data;
1567
0
    return NT_STATUS_OK;
1568
0
  }
1569
1570
0
  case FSCTL_GET_REPARSE_POINT:
1571
0
  {
1572
0
    uint32_t tag;
1573
0
    status = fsctl_get_reparse_point(
1574
0
      fsp, ctx, &tag, _out_data, max_out_len, out_len);
1575
0
    return status;
1576
0
  }
1577
1578
0
  case FSCTL_SET_REPARSE_POINT:
1579
0
  {
1580
0
    status = fsctl_set_reparse_point(fsp, ctx, _in_data, in_len);
1581
0
    return status;
1582
0
  }
1583
1584
0
  case FSCTL_DELETE_REPARSE_POINT:
1585
0
  {
1586
0
    status = fsctl_del_reparse_point(fsp, ctx, _in_data, in_len);
1587
0
    return status;
1588
0
  }
1589
1590
0
  case FSCTL_GET_SHADOW_COPY_DATA:
1591
0
  {
1592
    /*
1593
     * This is called to retrieve the number of Shadow Copies (a.k.a. snapshots)
1594
     * and return their volume names.  If max_data_count is 16, then it is just
1595
     * asking for the number of volumes and length of the combined names.
1596
     *
1597
     * pdata is the data allocated by our caller, but that uses
1598
     * total_data_count (which is 0 in our case) rather than max_data_count.
1599
     * Allocate the correct amount and return the pointer to let
1600
     * it be deallocated when we return.
1601
     */
1602
0
    struct shadow_copy_data *shadow_data = NULL;
1603
0
    bool labels = False;
1604
0
    uint32_t labels_data_count = 0;
1605
0
    uint32_t i;
1606
0
    char *cur_pdata = NULL;
1607
1608
0
    if (max_out_len < 16) {
1609
0
      DBG_ERR("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n",
1610
0
        max_out_len);
1611
0
      return NT_STATUS_INVALID_PARAMETER;
1612
0
    }
1613
1614
0
    if (max_out_len > 16) {
1615
0
      labels = True;
1616
0
    }
1617
1618
0
    shadow_data = talloc_zero(ctx, struct shadow_copy_data);
1619
0
    if (shadow_data == NULL) {
1620
0
      DBG_ERR("TALLOC_ZERO() failed!\n");
1621
0
      return NT_STATUS_NO_MEMORY;
1622
0
    }
1623
1624
    /*
1625
     * Call the VFS routine to actually do the work.
1626
     */
1627
0
    if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels)!=0) {
1628
0
      int log_lev = DBGLVL_ERR;
1629
0
      if (errno == 0) {
1630
        /* broken module didn't set errno on error */
1631
0
        status = NT_STATUS_UNSUCCESSFUL;
1632
0
      } else {
1633
0
        status = map_nt_error_from_unix(errno);
1634
0
        if (NT_STATUS_EQUAL(status,
1635
0
                NT_STATUS_NOT_SUPPORTED)) {
1636
0
          log_lev = DBGLVL_INFO;
1637
0
        }
1638
0
      }
1639
0
      DEBUG(log_lev, ("FSCTL_GET_SHADOW_COPY_DATA: "
1640
0
          "connectpath %s, failed - %s.\n",
1641
0
          fsp->conn->connectpath,
1642
0
          nt_errstr(status)));
1643
0
      TALLOC_FREE(shadow_data);
1644
0
      return status;
1645
0
    }
1646
1647
0
    labels_data_count = (shadow_data->num_volumes * 2 *
1648
0
          sizeof(SHADOW_COPY_LABEL)) + 2;
1649
1650
0
    if (!labels) {
1651
0
      *out_len = 16;
1652
0
    } else {
1653
0
      *out_len = 12 + labels_data_count;
1654
0
    }
1655
1656
0
    if (max_out_len < *out_len) {
1657
0
      DBG_ERR("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) too small (%u) bytes needed!\n",
1658
0
        max_out_len, *out_len);
1659
0
      TALLOC_FREE(shadow_data);
1660
0
      return NT_STATUS_BUFFER_TOO_SMALL;
1661
0
    }
1662
1663
0
    cur_pdata = talloc_zero_array(ctx, char, *out_len);
1664
0
    if (cur_pdata == NULL) {
1665
0
      TALLOC_FREE(shadow_data);
1666
0
      return NT_STATUS_NO_MEMORY;
1667
0
    }
1668
1669
0
    *out_data = cur_pdata;
1670
1671
    /* num_volumes 4 bytes */
1672
0
    SIVAL(cur_pdata, 0, shadow_data->num_volumes);
1673
1674
0
    if (labels) {
1675
      /* num_labels 4 bytes */
1676
0
      SIVAL(cur_pdata, 4, shadow_data->num_volumes);
1677
0
    }
1678
1679
    /* needed_data_count 4 bytes */
1680
0
    SIVAL(cur_pdata, 8, labels_data_count);
1681
1682
0
    cur_pdata += 12;
1683
1684
0
    DBG_DEBUG("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n",
1685
0
        shadow_data->num_volumes, fsp_str_dbg(fsp));
1686
0
    if (labels && shadow_data->labels) {
1687
0
      for (i=0; i<shadow_data->num_volumes; i++) {
1688
0
        size_t len = 0;
1689
0
        status = srvstr_push(cur_pdata, req_flags,
1690
0
              cur_pdata, shadow_data->labels[i],
1691
0
              2 * sizeof(SHADOW_COPY_LABEL),
1692
0
              STR_UNICODE|STR_TERMINATE, &len);
1693
0
        if (!NT_STATUS_IS_OK(status)) {
1694
0
          TALLOC_FREE(*out_data);
1695
0
          TALLOC_FREE(shadow_data);
1696
0
          return status;
1697
0
        }
1698
0
        cur_pdata += 2 * sizeof(SHADOW_COPY_LABEL);
1699
0
        DEBUGADD(DBGLVL_DEBUG,("Label[%u]: '%s'\n",i,shadow_data->labels[i]));
1700
0
      }
1701
0
    }
1702
1703
0
    TALLOC_FREE(shadow_data);
1704
1705
0
    return NT_STATUS_OK;
1706
0
  }
1707
1708
0
  case FSCTL_FIND_FILES_BY_SID:
1709
0
  {
1710
    /* pretend this succeeded -
1711
     *
1712
     * we have to send back a list with all files owned by this SID
1713
     *
1714
     * but I have to check that --metze
1715
     */
1716
0
    ssize_t ret;
1717
0
    struct dom_sid sid;
1718
0
    struct dom_sid_buf buf;
1719
0
    uid_t uid;
1720
0
    size_t sid_len;
1721
1722
0
    DBG_DEBUG("FSCTL_FIND_FILES_BY_SID: called on %s\n",
1723
0
         fsp_fnum_dbg(fsp));
1724
1725
0
    if (in_len < 8) {
1726
      /* NT_STATUS_BUFFER_TOO_SMALL maybe? */
1727
0
      return NT_STATUS_INVALID_PARAMETER;
1728
0
    }
1729
1730
0
    sid_len = MIN(in_len - 4,SID_MAX_SIZE);
1731
1732
    /* unknown 4 bytes: this is not the length of the sid :-(  */
1733
    /*unknown = IVAL(pdata,0);*/
1734
1735
0
    ret = sid_parse(_in_data + 4, sid_len, &sid);
1736
0
    if (ret == -1) {
1737
0
      return NT_STATUS_INVALID_PARAMETER;
1738
0
    }
1739
0
    DEBUGADD(DBGLVL_DEBUG, ("for SID: %s\n",
1740
0
            dom_sid_str_buf(&sid, &buf)));
1741
1742
0
    if (!sid_to_uid(&sid, &uid)) {
1743
0
      DBG_ERR("sid_to_uid: failed, sid[%s] sid_len[%lu]\n",
1744
0
         dom_sid_str_buf(&sid, &buf),
1745
0
         (unsigned long)sid_len);
1746
0
      uid = (-1);
1747
0
    }
1748
1749
    /* we can take a look at the find source :-)
1750
     *
1751
     * find ./ -uid $uid  -name '*'   is what we need here
1752
     *
1753
     *
1754
     * and send 4bytes len and then NULL terminated unicode strings
1755
     * for each file
1756
     *
1757
     * but I don't know how to deal with the paged results
1758
     * (maybe we can hang the result anywhere in the fsp struct)
1759
     *
1760
     * but I don't know how to deal with the paged results
1761
     * (maybe we can hang the result anywhere in the fsp struct)
1762
     *
1763
     * we don't send all files at once
1764
     * and at the next we should *not* start from the beginning,
1765
     * so we have to cache the result
1766
     *
1767
     * --metze
1768
     */
1769
1770
    /* this works for now... */
1771
0
    return NT_STATUS_OK;
1772
0
  }
1773
1774
0
  case FSCTL_QUERY_ALLOCATED_RANGES:
1775
0
  {
1776
    /* FIXME: This is just a dummy reply, telling that all of the
1777
     * file is allocated. MKS cp needs that.
1778
     * Adding the real allocated ranges via FIEMAP on Linux
1779
     * and SEEK_DATA/SEEK_HOLE on Solaris is needed to make
1780
     * this FSCTL correct for sparse files.
1781
     */
1782
0
    uint64_t offset, length;
1783
0
    char *out_data_tmp = NULL;
1784
1785
0
    if (in_len != 16) {
1786
0
      DBG_ERR("FSCTL_QUERY_ALLOCATED_RANGES: data_count(%u) != 16 is invalid!\n",
1787
0
        in_len);
1788
0
      return NT_STATUS_INVALID_PARAMETER;
1789
0
    }
1790
1791
0
    if (max_out_len < 16) {
1792
0
      DBG_ERR("FSCTL_QUERY_ALLOCATED_RANGES: max_out_len (%u) < 16 is invalid!\n",
1793
0
        max_out_len);
1794
0
      return NT_STATUS_INVALID_PARAMETER;
1795
0
    }
1796
1797
0
    offset = BVAL(in_data,0);
1798
0
    length = BVAL(in_data,8);
1799
1800
0
    if (offset + length < offset) {
1801
      /* No 64-bit integer wrap. */
1802
0
      return NT_STATUS_INVALID_PARAMETER;
1803
0
    }
1804
1805
    /* Shouldn't this be SMB_VFS_STAT ... ? */
1806
0
    status = vfs_stat_fsp(fsp);
1807
0
    if (!NT_STATUS_IS_OK(status)) {
1808
0
      return status;
1809
0
    }
1810
1811
0
    *out_len = 16;
1812
0
    out_data_tmp = talloc_array(ctx, char, *out_len);
1813
0
    if (out_data_tmp == NULL) {
1814
0
      DBG_DEBUG("unable to allocate memory for response\n");
1815
0
      return NT_STATUS_NO_MEMORY;
1816
0
    }
1817
1818
0
    if (offset > fsp->fsp_name->st.st_ex_size ||
1819
0
        fsp->fsp_name->st.st_ex_size == 0 ||
1820
0
        length == 0) {
1821
0
      memset(out_data_tmp, 0, *out_len);
1822
0
    } else {
1823
0
      uint64_t end = offset + length;
1824
0
      end = MIN(end, fsp->fsp_name->st.st_ex_size);
1825
0
      SBVAL(out_data_tmp, 0, 0);
1826
0
      SBVAL(out_data_tmp, 8, end);
1827
0
    }
1828
1829
0
    *out_data = out_data_tmp;
1830
1831
0
    return NT_STATUS_OK;
1832
0
  }
1833
1834
0
  case FSCTL_IS_VOLUME_DIRTY:
1835
0
  {
1836
0
    DBG_DEBUG("FSCTL_IS_VOLUME_DIRTY: called on %s "
1837
0
        "(but remotely not supported)\n", fsp_fnum_dbg(fsp));
1838
    /*
1839
     * http://msdn.microsoft.com/en-us/library/cc232128%28PROT.10%29.aspx
1840
     * says we have to respond with NT_STATUS_INVALID_PARAMETER
1841
     */
1842
0
    return NT_STATUS_INVALID_PARAMETER;
1843
0
  }
1844
1845
0
  default:
1846
    /*
1847
     * Only print once ... unfortunately there could be lots of
1848
     * different FSCTLs that are called.
1849
     */
1850
0
    if (!vfswrap_logged_ioctl_message) {
1851
0
      vfswrap_logged_ioctl_message = true;
1852
0
      DBG_NOTICE("%s (0x%x): Currently not implemented.\n",
1853
0
      __func__, function);
1854
0
    }
1855
0
  }
1856
1857
0
  return NT_STATUS_NOT_SUPPORTED;
1858
0
}
1859
1860
static bool vfswrap_is_offline(struct connection_struct *conn,
1861
             const struct smb_filename *fname);
1862
1863
struct vfswrap_get_dos_attributes_state {
1864
  struct vfs_aio_state aio_state;
1865
  connection_struct *conn;
1866
  TALLOC_CTX *mem_ctx;
1867
  struct tevent_context *ev;
1868
  files_struct *dir_fsp;
1869
  struct smb_filename *smb_fname;
1870
  uint32_t dosmode;
1871
  bool as_root;
1872
};
1873
1874
static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq);
1875
1876
static struct tevent_req *vfswrap_get_dos_attributes_send(
1877
      TALLOC_CTX *mem_ctx,
1878
      struct tevent_context *ev,
1879
      struct vfs_handle_struct *handle,
1880
      files_struct *dir_fsp,
1881
      struct smb_filename *smb_fname)
1882
0
{
1883
0
  struct tevent_req *req = NULL;
1884
0
  struct tevent_req *subreq = NULL;
1885
0
  struct vfswrap_get_dos_attributes_state *state = NULL;
1886
1887
0
  SMB_ASSERT(!is_named_stream(smb_fname));
1888
1889
0
  req = tevent_req_create(mem_ctx, &state,
1890
0
        struct vfswrap_get_dos_attributes_state);
1891
0
  if (req == NULL) {
1892
0
    return NULL;
1893
0
  }
1894
1895
0
  *state = (struct vfswrap_get_dos_attributes_state) {
1896
0
    .conn = dir_fsp->conn,
1897
0
    .mem_ctx = mem_ctx,
1898
0
    .ev = ev,
1899
0
    .dir_fsp = dir_fsp,
1900
0
    .smb_fname = smb_fname,
1901
0
  };
1902
1903
0
  if (!lp_store_dos_attributes(SNUM(dir_fsp->conn))) {
1904
0
    DBG_ERR("%s: \"smbd async dosmode\" enabled, but "
1905
0
      "\"store dos attributes\" is disabled\n",
1906
0
      dir_fsp->conn->connectpath);
1907
0
    tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
1908
0
    return tevent_req_post(req, ev);
1909
0
  }
1910
1911
0
  subreq = SMB_VFS_GETXATTRAT_SEND(state,
1912
0
           ev,
1913
0
           dir_fsp,
1914
0
           smb_fname,
1915
0
           SAMBA_XATTR_DOS_ATTRIB,
1916
0
           sizeof(fstring));
1917
0
  if (tevent_req_nomem(subreq, req)) {
1918
0
    return tevent_req_post(req, ev);
1919
0
  }
1920
0
  tevent_req_set_callback(subreq,
1921
0
        vfswrap_get_dos_attributes_getxattr_done,
1922
0
        req);
1923
1924
0
  return req;
1925
0
}
1926
1927
static void vfswrap_get_dos_attributes_getxattr_done(struct tevent_req *subreq)
1928
0
{
1929
0
  struct tevent_req *req =
1930
0
    tevent_req_callback_data(subreq,
1931
0
    struct tevent_req);
1932
0
  struct vfswrap_get_dos_attributes_state *state =
1933
0
    tevent_req_data(req,
1934
0
    struct vfswrap_get_dos_attributes_state);
1935
0
  ssize_t xattr_size;
1936
0
  DATA_BLOB blob = {0};
1937
0
  char *path = NULL;
1938
0
  char *tofree = NULL;
1939
0
  char pathbuf[PATH_MAX+1];
1940
0
  ssize_t pathlen;
1941
0
  struct smb_filename smb_fname;
1942
0
  bool offline;
1943
0
  NTSTATUS status;
1944
1945
0
  xattr_size = SMB_VFS_GETXATTRAT_RECV(subreq,
1946
0
               &state->aio_state,
1947
0
               state,
1948
0
               &blob.data);
1949
0
  TALLOC_FREE(subreq);
1950
0
  if (xattr_size == -1) {
1951
0
    status = map_nt_error_from_unix(state->aio_state.error);
1952
1953
0
    if (state->as_root) {
1954
0
      tevent_req_nterror(req, status);
1955
0
      return;
1956
0
    }
1957
0
    if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1958
0
      tevent_req_nterror(req, status);
1959
0
      return;
1960
0
    }
1961
1962
0
    state->as_root = true;
1963
1964
0
    become_root();
1965
0
    subreq = SMB_VFS_GETXATTRAT_SEND(state,
1966
0
             state->ev,
1967
0
             state->dir_fsp,
1968
0
             state->smb_fname,
1969
0
             SAMBA_XATTR_DOS_ATTRIB,
1970
0
             sizeof(fstring));
1971
0
    unbecome_root();
1972
0
    if (tevent_req_nomem(subreq, req)) {
1973
0
      return;
1974
0
    }
1975
0
    tevent_req_set_callback(subreq,
1976
0
          vfswrap_get_dos_attributes_getxattr_done,
1977
0
          req);
1978
0
    return;
1979
0
  }
1980
1981
0
  blob.length = xattr_size;
1982
1983
0
  status = parse_dos_attribute_blob(state->smb_fname,
1984
0
            blob,
1985
0
            &state->dosmode);
1986
0
  if (!NT_STATUS_IS_OK(status)) {
1987
0
    tevent_req_nterror(req, status);
1988
0
    return;
1989
0
  }
1990
1991
0
  pathlen = full_path_tos(state->dir_fsp->fsp_name->base_name,
1992
0
        state->smb_fname->base_name,
1993
0
        pathbuf,
1994
0
        sizeof(pathbuf),
1995
0
        &path,
1996
0
        &tofree);
1997
0
  if (pathlen == -1) {
1998
0
    tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1999
0
    return;
2000
0
  }
2001
2002
0
  smb_fname = (struct smb_filename) {
2003
0
    .base_name = path,
2004
0
    .st = state->smb_fname->st,
2005
0
    .flags = state->smb_fname->flags,
2006
0
    .twrp = state->smb_fname->twrp,
2007
0
  };
2008
2009
0
  offline = vfswrap_is_offline(state->conn, &smb_fname);
2010
0
  if (offline) {
2011
0
    state->dosmode |= FILE_ATTRIBUTE_OFFLINE;
2012
0
  }
2013
0
  TALLOC_FREE(tofree);
2014
2015
0
  tevent_req_done(req);
2016
0
  return;
2017
0
}
2018
2019
static NTSTATUS vfswrap_get_dos_attributes_recv(struct tevent_req *req,
2020
            struct vfs_aio_state *aio_state,
2021
            uint32_t *dosmode)
2022
0
{
2023
0
  struct vfswrap_get_dos_attributes_state *state =
2024
0
    tevent_req_data(req,
2025
0
    struct vfswrap_get_dos_attributes_state);
2026
0
  NTSTATUS status;
2027
2028
0
  if (tevent_req_is_nterror(req, &status)) {
2029
0
    tevent_req_received(req);
2030
0
    return status;
2031
0
  }
2032
2033
0
  *aio_state = state->aio_state;
2034
0
  *dosmode = state->dosmode;
2035
0
  tevent_req_received(req);
2036
0
  return NT_STATUS_OK;
2037
0
}
2038
2039
static NTSTATUS vfswrap_fget_dos_attributes(struct vfs_handle_struct *handle,
2040
              struct files_struct *fsp,
2041
              uint32_t *dosmode)
2042
0
{
2043
0
  bool offline;
2044
2045
0
  SMB_ASSERT(!fsp_is_alternate_stream(fsp));
2046
2047
0
  offline = vfswrap_is_offline(handle->conn, fsp->fsp_name);
2048
0
  if (offline) {
2049
0
    *dosmode |= FILE_ATTRIBUTE_OFFLINE;
2050
0
  }
2051
2052
0
  return fget_ea_dos_attribute(fsp, dosmode);
2053
0
}
2054
2055
static NTSTATUS vfswrap_fset_dos_attributes(struct vfs_handle_struct *handle,
2056
              struct files_struct *fsp,
2057
              uint32_t dosmode)
2058
0
{
2059
0
  SMB_ASSERT(!fsp_is_alternate_stream(fsp));
2060
2061
0
  return set_ea_dos_attribute(handle->conn, fsp->fsp_name, dosmode);
2062
0
}
2063
2064
static struct vfs_offload_ctx *vfswrap_offload_ctx;
2065
2066
struct vfswrap_offload_read_state {
2067
  DATA_BLOB token;
2068
};
2069
2070
static struct tevent_req *vfswrap_offload_read_send(
2071
  TALLOC_CTX *mem_ctx,
2072
  struct tevent_context *ev,
2073
  struct vfs_handle_struct *handle,
2074
  struct files_struct *fsp,
2075
  uint32_t fsctl,
2076
  uint32_t ttl,
2077
  off_t offset,
2078
  size_t to_copy)
2079
0
{
2080
0
  struct tevent_req *req = NULL;
2081
0
  struct vfswrap_offload_read_state *state = NULL;
2082
0
  NTSTATUS status;
2083
2084
0
  req = tevent_req_create(mem_ctx, &state,
2085
0
        struct vfswrap_offload_read_state);
2086
0
  if (req == NULL) {
2087
0
    return NULL;
2088
0
  }
2089
2090
0
  status = vfs_offload_token_ctx_init(fsp->conn->sconn->client,
2091
0
              &vfswrap_offload_ctx);
2092
0
  if (tevent_req_nterror(req, status)) {
2093
0
    return tevent_req_post(req, ev);
2094
0
  }
2095
2096
0
  if (fsctl != FSCTL_SRV_REQUEST_RESUME_KEY &&
2097
0
      fsctl != FSCTL_DUP_EXTENTS_TO_FILE)
2098
0
  {
2099
0
    tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
2100
0
    return tevent_req_post(req, ev);
2101
0
  }
2102
2103
0
  if (fsctl == FSCTL_DUP_EXTENTS_TO_FILE &&
2104
0
      !(fsp->conn->fs_capabilities & FILE_SUPPORTS_BLOCK_REFCOUNTING))
2105
0
  {
2106
0
    tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
2107
0
    return tevent_req_post(req, ev);
2108
0
  }
2109
2110
0
  status = vfs_offload_token_create_blob(state, fsp, fsctl,
2111
0
                 &state->token);
2112
0
  if (tevent_req_nterror(req, status)) {
2113
0
    return tevent_req_post(req, ev);
2114
0
  }
2115
2116
0
  status = vfs_offload_token_db_store_fsp(vfswrap_offload_ctx, fsp,
2117
0
            &state->token);
2118
0
  if (tevent_req_nterror(req, status)) {
2119
0
    return tevent_req_post(req, ev);
2120
0
  }
2121
2122
0
  tevent_req_done(req);
2123
0
  return tevent_req_post(req, ev);
2124
0
}
2125
2126
static NTSTATUS vfswrap_offload_read_recv(struct tevent_req *req,
2127
            struct vfs_handle_struct *handle,
2128
            TALLOC_CTX *mem_ctx,
2129
            uint32_t *flags,
2130
            uint64_t *xferlen,
2131
            DATA_BLOB *token)
2132
0
{
2133
0
  struct vfswrap_offload_read_state *state = tevent_req_data(
2134
0
    req, struct vfswrap_offload_read_state);
2135
0
  NTSTATUS status;
2136
2137
0
  if (tevent_req_is_nterror(req, &status)) {
2138
0
    tevent_req_received(req);
2139
0
    return status;
2140
0
  }
2141
2142
0
  *flags = 0;
2143
0
  *xferlen = 0;
2144
0
  token->length = state->token.length;
2145
0
  token->data = talloc_move(mem_ctx, &state->token.data);
2146
2147
0
  tevent_req_received(req);
2148
0
  return NT_STATUS_OK;
2149
0
}
2150
2151
struct vfswrap_offload_write_state {
2152
  uint8_t *buf;
2153
  bool read_lck_locked;
2154
  bool write_lck_locked;
2155
  DATA_BLOB *token;
2156
  struct tevent_context *src_ev;
2157
  struct files_struct *src_fsp;
2158
  off_t src_off;
2159
  struct tevent_context *dst_ev;
2160
  struct files_struct *dst_fsp;
2161
  off_t dst_off;
2162
  off_t to_copy;
2163
  off_t remaining;
2164
  off_t copied;
2165
  size_t next_io_size;
2166
};
2167
2168
static void vfswrap_offload_write_cleanup(struct tevent_req *req,
2169
            enum tevent_req_state req_state)
2170
0
{
2171
0
  struct vfswrap_offload_write_state *state = tevent_req_data(
2172
0
    req, struct vfswrap_offload_write_state);
2173
0
  bool ok;
2174
2175
0
  if (state->dst_fsp == NULL) {
2176
0
    return;
2177
0
  }
2178
2179
0
  ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2180
0
  SMB_ASSERT(ok);
2181
0
  state->dst_fsp = NULL;
2182
0
}
2183
2184
static NTSTATUS vfswrap_offload_fast_copy(struct tevent_req *req, int fsctl);
2185
static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req);
2186
2187
static struct tevent_req *vfswrap_offload_write_send(
2188
  struct vfs_handle_struct *handle,
2189
  TALLOC_CTX *mem_ctx,
2190
  struct tevent_context *ev,
2191
  uint32_t fsctl,
2192
  DATA_BLOB *token,
2193
  off_t transfer_offset,
2194
  struct files_struct *dest_fsp,
2195
  off_t dest_off,
2196
  off_t to_copy)
2197
0
{
2198
0
  struct tevent_req *req;
2199
0
  struct vfswrap_offload_write_state *state = NULL;
2200
  /* off_t is signed! */
2201
0
  off_t max_offset = INT64_MAX - to_copy;
2202
0
  off_t num = to_copy;
2203
0
  files_struct *src_fsp = NULL;
2204
0
  NTSTATUS status;
2205
0
  bool ok;
2206
2207
0
  req = tevent_req_create(mem_ctx, &state,
2208
0
        struct vfswrap_offload_write_state);
2209
0
  if (req == NULL) {
2210
0
    return NULL;
2211
0
  }
2212
2213
0
  *state = (struct vfswrap_offload_write_state) {
2214
0
    .token = token,
2215
0
    .src_off = transfer_offset,
2216
0
    .dst_ev = ev,
2217
0
    .dst_fsp = dest_fsp,
2218
0
    .dst_off = dest_off,
2219
0
    .to_copy = to_copy,
2220
0
    .remaining = to_copy,
2221
0
  };
2222
2223
0
  status = vfs_offload_token_ctx_init(handle->conn->sconn->client,
2224
0
              &vfswrap_offload_ctx);
2225
0
  if (tevent_req_nterror(req, status)) {
2226
0
    return tevent_req_post(req, ev);
2227
0
  }
2228
2229
0
  tevent_req_set_cleanup_fn(req, vfswrap_offload_write_cleanup);
2230
2231
0
  switch (fsctl) {
2232
0
  case FSCTL_DUP_EXTENTS_TO_FILE:
2233
0
    break;
2234
2235
0
  case FSCTL_SRV_COPYCHUNK:
2236
0
  case FSCTL_SRV_COPYCHUNK_WRITE:
2237
0
    num = MIN(to_copy, COPYCHUNK_MAX_TOTAL_LEN);
2238
0
    break;
2239
2240
0
  case FSCTL_OFFLOAD_WRITE:
2241
0
    tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
2242
0
    return tevent_req_post(req, ev);
2243
2244
0
  default:
2245
0
    tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2246
0
    return tevent_req_post(req, ev);
2247
0
  }
2248
2249
0
  if (to_copy == 0) {
2250
0
    tevent_req_done(req);
2251
0
    return tevent_req_post(req, ev);
2252
0
  }
2253
2254
0
  if (state->src_off > max_offset) {
2255
    /*
2256
     * Protect integer checks below.
2257
     */
2258
0
    tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2259
0
    return tevent_req_post(req, ev);
2260
0
  }
2261
0
  if (state->src_off < 0) {
2262
    /*
2263
     * Protect integer checks below.
2264
     */
2265
0
    tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2266
0
    return tevent_req_post(req, ev);
2267
0
  }
2268
0
  if (state->dst_off > max_offset) {
2269
    /*
2270
     * Protect integer checks below.
2271
     */
2272
0
    tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2273
0
    return tevent_req_post(req, ev);
2274
0
  }
2275
0
  if (state->dst_off < 0) {
2276
    /*
2277
     * Protect integer checks below.
2278
     */
2279
0
    tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2280
0
    return tevent_req_post(req, ev);
2281
0
  }
2282
2283
0
  status = vfs_offload_token_db_fetch_fsp(vfswrap_offload_ctx,
2284
0
            token, &src_fsp);
2285
0
  if (tevent_req_nterror(req, status)) {
2286
0
    return tevent_req_post(req, ev);
2287
0
  }
2288
2289
0
  DBG_DEBUG("server side copy (%s) of length %" PRIu64 "\n",
2290
0
      fsctl == FSCTL_DUP_EXTENTS_TO_FILE ? "reflink" : "chunk",
2291
0
      to_copy);
2292
2293
0
  status = vfs_offload_token_check_handles(fsctl, src_fsp, dest_fsp);
2294
0
  if (!NT_STATUS_IS_OK(status)) {
2295
0
    tevent_req_nterror(req, status);
2296
0
    return tevent_req_post(req, ev);
2297
0
  }
2298
2299
0
  ok = change_to_user_and_service_by_fsp(src_fsp);
2300
0
  if (!ok) {
2301
0
    tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
2302
0
    return tevent_req_post(req, ev);
2303
0
  }
2304
2305
0
  state->src_ev = src_fsp->conn->sconn->ev_ctx;
2306
0
  state->src_fsp = src_fsp;
2307
2308
0
  status = vfs_stat_fsp(src_fsp);
2309
0
  if (tevent_req_nterror(req, status)) {
2310
0
    return tevent_req_post(req, ev);
2311
0
  }
2312
2313
0
  if (src_fsp->fsp_name->st.st_ex_size < state->src_off + to_copy) {
2314
    /*
2315
     * [MS-SMB2] 3.3.5.15.6 Handling a Server-Side Data Copy Request
2316
     *   If the SourceOffset or SourceOffset + Length extends beyond
2317
     *   the end of file, the server SHOULD<240> treat this as a
2318
     *   STATUS_END_OF_FILE error.
2319
     * ...
2320
     *   <240> Section 3.3.5.15.6: Windows servers will return
2321
     *   STATUS_INVALID_VIEW_SIZE instead of STATUS_END_OF_FILE.
2322
     */
2323
0
    tevent_req_nterror(req, NT_STATUS_INVALID_VIEW_SIZE);
2324
0
    return tevent_req_post(req, ev);
2325
0
  }
2326
2327
0
  status = vfswrap_offload_fast_copy(req, fsctl);
2328
0
  if (NT_STATUS_IS_OK(status)) {
2329
0
    tevent_req_done(req);
2330
0
    return tevent_req_post(req, ev);
2331
0
  }
2332
0
  if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
2333
0
    tevent_req_nterror(req, status);
2334
0
    return tevent_req_post(req, ev);
2335
0
  }
2336
2337
0
  state->buf = talloc_array(state, uint8_t, num);
2338
0
  if (tevent_req_nomem(state->buf, req)) {
2339
0
    return tevent_req_post(req, ev);
2340
0
  }
2341
2342
0
  status = vfswrap_offload_write_loop(req);
2343
0
  if (!NT_STATUS_IS_OK(status)) {
2344
0
    tevent_req_nterror(req, status);
2345
0
    return tevent_req_post(req, ev);
2346
0
  }
2347
2348
0
  return req;
2349
0
}
2350
2351
static NTSTATUS vfswrap_offload_fast_copy(struct tevent_req *req, int fsctl)
2352
0
{
2353
0
  struct vfswrap_offload_write_state *state = tevent_req_data(
2354
0
    req, struct vfswrap_offload_write_state);
2355
0
  struct lock_struct lck;
2356
0
  ssize_t nwritten;
2357
0
  NTSTATUS status;
2358
0
  bool same_file;
2359
0
  bool ok;
2360
0
  static bool try_copy_file_range = true;
2361
2362
0
  same_file = file_id_equal(&state->src_fsp->file_id,
2363
0
          &state->dst_fsp->file_id);
2364
0
  if (same_file &&
2365
0
      sys_io_ranges_overlap(state->remaining,
2366
0
          state->src_off,
2367
0
          state->remaining,
2368
0
          state->dst_off))
2369
0
  {
2370
0
    if (fsctl == FSCTL_DUP_EXTENTS_TO_FILE) {
2371
0
      return NT_STATUS_INVALID_PARAMETER;
2372
0
    }
2373
0
    return NT_STATUS_MORE_PROCESSING_REQUIRED;
2374
0
  }
2375
2376
0
  if (fsp_is_alternate_stream(state->src_fsp) ||
2377
0
      fsp_is_alternate_stream(state->dst_fsp))
2378
0
  {
2379
0
    if (fsctl == FSCTL_DUP_EXTENTS_TO_FILE) {
2380
0
      return NT_STATUS_NOT_SUPPORTED;
2381
0
    }
2382
0
    return NT_STATUS_MORE_PROCESSING_REQUIRED;
2383
0
  }
2384
2385
0
  if (fsctl == FSCTL_DUP_EXTENTS_TO_FILE) {
2386
0
    int ret;
2387
2388
0
    ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2389
0
    if (!ok) {
2390
0
      return NT_STATUS_INTERNAL_ERROR;
2391
0
    }
2392
2393
0
    ret = copy_reflink(fsp_get_io_fd(state->src_fsp),
2394
0
           state->src_off,
2395
0
           fsp_get_io_fd(state->dst_fsp),
2396
0
           state->dst_off,
2397
0
           state->to_copy);
2398
0
    if (ret == -1) {
2399
0
      DBG_INFO("copy_reflink() failed: %s\n", strerror(errno));
2400
0
      return map_nt_error_from_unix(errno);
2401
0
    }
2402
2403
0
    state->copied = state->to_copy;
2404
0
    goto done;
2405
0
  }
2406
2407
0
  if (!try_copy_file_range) {
2408
0
    return NT_STATUS_MORE_PROCESSING_REQUIRED;
2409
0
  }
2410
2411
0
  init_strict_lock_struct(state->src_fsp,
2412
0
        state->src_fsp->op->global->open_persistent_id,
2413
0
        state->src_off,
2414
0
        state->remaining,
2415
0
        READ_LOCK,
2416
0
        &lck);
2417
2418
0
  ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2419
0
         state->src_fsp,
2420
0
         &lck);
2421
0
  if (!ok) {
2422
0
    return NT_STATUS_FILE_LOCK_CONFLICT;
2423
0
  }
2424
2425
0
  ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2426
0
  if (!ok) {
2427
0
    return NT_STATUS_INTERNAL_ERROR;
2428
0
  }
2429
2430
0
  init_strict_lock_struct(state->dst_fsp,
2431
0
        state->dst_fsp->op->global->open_persistent_id,
2432
0
        state->dst_off,
2433
0
        state->remaining,
2434
0
        WRITE_LOCK,
2435
0
        &lck);
2436
2437
0
  ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2438
0
               state->dst_fsp,
2439
0
               &lck);
2440
0
  if (!ok) {
2441
0
    return NT_STATUS_FILE_LOCK_CONFLICT;
2442
0
  }
2443
2444
0
  while (state->remaining > 0) {
2445
0
    nwritten = copy_file_range(fsp_get_io_fd(state->src_fsp),
2446
0
             &state->src_off,
2447
0
             fsp_get_io_fd(state->dst_fsp),
2448
0
             &state->dst_off,
2449
0
             state->remaining,
2450
0
             0);
2451
0
    if (nwritten == -1) {
2452
0
      DBG_DEBUG("copy_file_range src [%s]:[%jd] dst [%s]:[%jd] "
2453
0
          "n [%jd] failed: %s\n",
2454
0
          fsp_str_dbg(state->src_fsp),
2455
0
          (intmax_t)state->src_off,
2456
0
          fsp_str_dbg(state->dst_fsp),
2457
0
          (intmax_t)state->dst_off,
2458
0
          (intmax_t)state->remaining,
2459
0
          strerror(errno));
2460
0
      switch (errno) {
2461
0
      case EOPNOTSUPP:
2462
0
      case ENOSYS:
2463
0
        try_copy_file_range = false;
2464
0
        status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2465
0
        break;
2466
0
      case EXDEV:
2467
0
        status = NT_STATUS_MORE_PROCESSING_REQUIRED;
2468
0
        break;
2469
0
      default:
2470
0
        status = map_nt_error_from_unix(errno);
2471
0
        if (NT_STATUS_EQUAL(
2472
0
              status,
2473
0
              NT_STATUS_MORE_PROCESSING_REQUIRED))
2474
0
        {
2475
          /* Avoid triggering the fallback */
2476
0
          status = NT_STATUS_INTERNAL_ERROR;
2477
0
        }
2478
0
        break;
2479
0
      }
2480
0
      return status;
2481
0
    }
2482
2483
0
    if (state->remaining < nwritten) {
2484
0
      DBG_DEBUG("copy_file_range src [%s] dst [%s] "
2485
0
          "n [%jd] remaining [%jd]\n",
2486
0
          fsp_str_dbg(state->src_fsp),
2487
0
          fsp_str_dbg(state->dst_fsp),
2488
0
          (intmax_t)nwritten,
2489
0
          (intmax_t)state->remaining);
2490
0
      return NT_STATUS_INTERNAL_ERROR;
2491
0
    }
2492
2493
0
    if (nwritten == 0) {
2494
0
      break;
2495
0
    }
2496
0
    state->copied += nwritten;
2497
0
    state->remaining -= nwritten;
2498
0
  }
2499
2500
0
done:
2501
  /*
2502
   * Tell the req cleanup function there's no need to call
2503
   * change_to_user_and_service_by_fsp() on the dst handle.
2504
   */
2505
0
  state->dst_fsp = NULL;
2506
0
  return NT_STATUS_OK;
2507
0
}
2508
2509
static void vfswrap_offload_write_read_done(struct tevent_req *subreq);
2510
2511
static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req)
2512
0
{
2513
0
  struct vfswrap_offload_write_state *state = tevent_req_data(
2514
0
    req, struct vfswrap_offload_write_state);
2515
0
  struct tevent_req *subreq = NULL;
2516
0
  struct lock_struct read_lck;
2517
0
  bool ok;
2518
2519
  /*
2520
   * This is called under the context of state->src_fsp.
2521
   */
2522
2523
0
  state->next_io_size = MIN(state->remaining, talloc_array_length(state->buf));
2524
2525
0
  init_strict_lock_struct(state->src_fsp,
2526
0
        state->src_fsp->op->global->open_persistent_id,
2527
0
        state->src_off,
2528
0
        state->next_io_size,
2529
0
        READ_LOCK,
2530
0
        &read_lck);
2531
2532
0
  ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
2533
0
         state->src_fsp,
2534
0
         &read_lck);
2535
0
  if (!ok) {
2536
0
    return NT_STATUS_FILE_LOCK_CONFLICT;
2537
0
  }
2538
2539
0
  subreq = SMB_VFS_PREAD_SEND(state,
2540
0
            state->src_ev,
2541
0
            state->src_fsp,
2542
0
            state->buf,
2543
0
            state->next_io_size,
2544
0
            state->src_off);
2545
0
  if (subreq == NULL) {
2546
0
    return NT_STATUS_NO_MEMORY;
2547
0
  }
2548
0
  tevent_req_set_callback(subreq, vfswrap_offload_write_read_done, req);
2549
2550
0
  return NT_STATUS_OK;
2551
0
}
2552
2553
static void vfswrap_offload_write_write_done(struct tevent_req *subreq);
2554
2555
static void vfswrap_offload_write_read_done(struct tevent_req *subreq)
2556
0
{
2557
0
  struct tevent_req *req = tevent_req_callback_data(
2558
0
    subreq, struct tevent_req);
2559
0
  struct vfswrap_offload_write_state *state = tevent_req_data(
2560
0
    req, struct vfswrap_offload_write_state);
2561
0
  struct vfs_aio_state aio_state;
2562
0
  struct lock_struct write_lck;
2563
0
  ssize_t nread;
2564
0
  bool ok;
2565
2566
0
  nread = SMB_VFS_PREAD_RECV(subreq, &aio_state);
2567
0
  TALLOC_FREE(subreq);
2568
0
  if (nread == -1) {
2569
0
    DBG_ERR("read failed: %s\n", strerror(aio_state.error));
2570
0
    tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2571
0
    return;
2572
0
  }
2573
0
  if (nread != state->next_io_size) {
2574
0
    DBG_ERR("Short read, only %zd of %zu\n",
2575
0
      nread, state->next_io_size);
2576
0
    tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2577
0
    return;
2578
0
  }
2579
2580
0
  state->src_off += nread;
2581
2582
0
  ok = change_to_user_and_service_by_fsp(state->dst_fsp);
2583
0
  if (!ok) {
2584
0
    tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2585
0
    return;
2586
0
  }
2587
2588
0
  init_strict_lock_struct(state->dst_fsp,
2589
0
        state->dst_fsp->op->global->open_persistent_id,
2590
0
        state->dst_off,
2591
0
        state->next_io_size,
2592
0
        WRITE_LOCK,
2593
0
        &write_lck);
2594
2595
0
  ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
2596
0
         state->dst_fsp,
2597
0
         &write_lck);
2598
0
  if (!ok) {
2599
0
    tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
2600
0
    return;
2601
0
  }
2602
2603
0
  subreq = SMB_VFS_PWRITE_SEND(state,
2604
0
             state->dst_ev,
2605
0
             state->dst_fsp,
2606
0
             state->buf,
2607
0
             state->next_io_size,
2608
0
             state->dst_off);
2609
0
  if (subreq == NULL) {
2610
0
    tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
2611
0
    return;
2612
0
  }
2613
0
  tevent_req_set_callback(subreq, vfswrap_offload_write_write_done, req);
2614
0
}
2615
2616
static void vfswrap_offload_write_write_done(struct tevent_req *subreq)
2617
0
{
2618
0
  struct tevent_req *req = tevent_req_callback_data(
2619
0
    subreq, struct tevent_req);
2620
0
  struct vfswrap_offload_write_state *state = tevent_req_data(
2621
0
    req, struct vfswrap_offload_write_state);
2622
0
  struct vfs_aio_state aio_state;
2623
0
  ssize_t nwritten;
2624
0
  NTSTATUS status;
2625
0
  bool ok;
2626
2627
0
  nwritten = SMB_VFS_PWRITE_RECV(subreq, &aio_state);
2628
0
  TALLOC_FREE(subreq);
2629
0
  if (nwritten == -1) {
2630
0
    DBG_ERR("write failed: %s\n", strerror(aio_state.error));
2631
0
    tevent_req_nterror(req, map_nt_error_from_unix(aio_state.error));
2632
0
    return;
2633
0
  }
2634
0
  if (nwritten != state->next_io_size) {
2635
0
    DBG_ERR("Short write, only %zd of %zu\n", nwritten, state->next_io_size);
2636
0
    tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
2637
0
    return;
2638
0
  }
2639
2640
0
  state->dst_off += nwritten;
2641
2642
0
  if (state->remaining < nwritten) {
2643
    /* Paranoia check */
2644
0
    tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2645
0
    return;
2646
0
  }
2647
0
  state->copied += nwritten;
2648
0
  state->remaining -= nwritten;
2649
0
  if (state->remaining == 0) {
2650
0
    tevent_req_done(req);
2651
0
    return;
2652
0
  }
2653
2654
0
  ok = change_to_user_and_service_by_fsp(state->src_fsp);
2655
0
  if (!ok) {
2656
0
    tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
2657
0
    return;
2658
0
  }
2659
2660
0
  status = vfswrap_offload_write_loop(req);
2661
0
  if (!NT_STATUS_IS_OK(status)) {
2662
0
    tevent_req_nterror(req, status);
2663
0
    return;
2664
0
  }
2665
2666
0
  return;
2667
0
}
2668
2669
static NTSTATUS vfswrap_offload_write_recv(struct vfs_handle_struct *handle,
2670
          struct tevent_req *req,
2671
          off_t *copied)
2672
0
{
2673
0
  struct vfswrap_offload_write_state *state = tevent_req_data(
2674
0
    req, struct vfswrap_offload_write_state);
2675
0
  NTSTATUS status;
2676
2677
0
  if (tevent_req_is_nterror(req, &status)) {
2678
0
    DBG_DEBUG("copy chunk failed: %s\n", nt_errstr(status));
2679
0
    *copied = 0;
2680
0
    tevent_req_received(req);
2681
0
    return status;
2682
0
  }
2683
2684
0
  *copied = state->copied;
2685
0
  DBG_DEBUG("copy chunk copied %lu\n", (unsigned long)*copied);
2686
0
  tevent_req_received(req);
2687
2688
0
  return NT_STATUS_OK;
2689
0
}
2690
2691
static NTSTATUS vfswrap_fget_compression(struct vfs_handle_struct *handle,
2692
          TALLOC_CTX *mem_ctx,
2693
          struct files_struct *fsp,
2694
          uint16_t *_compression_fmt)
2695
0
{
2696
0
  return NT_STATUS_INVALID_DEVICE_REQUEST;
2697
0
}
2698
2699
static NTSTATUS vfswrap_set_compression(struct vfs_handle_struct *handle,
2700
          TALLOC_CTX *mem_ctx,
2701
          struct files_struct *fsp,
2702
          uint16_t compression_fmt)
2703
0
{
2704
0
  return NT_STATUS_INVALID_DEVICE_REQUEST;
2705
0
}
2706
2707
/********************************************************************
2708
 Given a stat buffer return the allocated size on disk, taking into
2709
 account sparse files.
2710
********************************************************************/
2711
static uint64_t vfswrap_get_alloc_size(vfs_handle_struct *handle,
2712
               struct files_struct *fsp,
2713
               const SMB_STRUCT_STAT *sbuf)
2714
0
{
2715
0
  uint64_t result;
2716
2717
0
  START_PROFILE_X(SNUM(handle->conn), syscall_get_alloc_size);
2718
2719
0
  if(S_ISDIR(sbuf->st_ex_mode)) {
2720
0
    result = 0;
2721
0
    goto out;
2722
0
  }
2723
2724
0
#if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
2725
  /* The type of st_blocksize is blkcnt_t which *MUST* be
2726
     signed (according to POSIX) and can be less than 64-bits.
2727
     Ensure when we're converting to 64 bits wide we don't
2728
     sign extend. */
2729
0
#if defined(SIZEOF_BLKCNT_T_8)
2730
0
  result = (uint64_t)STAT_ST_BLOCKSIZE * (uint64_t)sbuf->st_ex_blocks;
2731
#elif defined(SIZEOF_BLKCNT_T_4)
2732
  {
2733
    uint64_t bs = ((uint64_t)sbuf->st_ex_blocks) & 0xFFFFFFFFLL;
2734
    result = (uint64_t)STAT_ST_BLOCKSIZE * bs;
2735
  }
2736
#else
2737
#error SIZEOF_BLKCNT_T_NOT_A_SUPPORTED_VALUE
2738
#endif
2739
0
  if (result == 0) {
2740
    /*
2741
     * Some file systems do not allocate a block for very
2742
     * small files. But for non-empty file should report a
2743
     * positive size.
2744
     */
2745
2746
0
    uint64_t filesize = get_file_size_stat(sbuf);
2747
0
    if (filesize > 0) {
2748
0
      result = MIN((uint64_t)STAT_ST_BLOCKSIZE, filesize);
2749
0
    }
2750
0
  }
2751
#else
2752
  result = get_file_size_stat(sbuf);
2753
#endif
2754
2755
0
  if (fsp && fsp->initial_allocation_size)
2756
0
    result = MAX(result,fsp->initial_allocation_size);
2757
2758
0
  result = smb_roundup(handle->conn, result);
2759
2760
0
 out:
2761
0
   END_PROFILE_X(syscall_get_alloc_size);
2762
0
   return result;
2763
0
}
2764
2765
static int vfswrap_unlinkat(vfs_handle_struct *handle,
2766
      struct files_struct *dirfsp,
2767
      const struct smb_filename *smb_fname,
2768
      int flags)
2769
0
{
2770
0
  int result = -1;
2771
2772
0
  START_PROFILE_X(SNUM(handle->conn), syscall_unlinkat);
2773
2774
0
  SMB_ASSERT(!is_named_stream(smb_fname));
2775
2776
0
  result = unlinkat(fsp_get_pathref_fd(dirfsp),
2777
0
      smb_fname->base_name,
2778
0
      flags);
2779
2780
0
  END_PROFILE_X(syscall_unlinkat);
2781
0
  return result;
2782
0
}
2783
2784
static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
2785
0
{
2786
0
  int result;
2787
2788
0
  START_PROFILE_X(SNUM(handle->conn), syscall_fchmod);
2789
2790
0
  if (!fsp->fsp_flags.is_pathref) {
2791
0
    result = fchmod(fsp_get_io_fd(fsp), mode);
2792
0
    END_PROFILE_X(syscall_fchmod);
2793
0
    return result;
2794
0
  }
2795
2796
0
  if (fsp->fsp_flags.have_proc_fds) {
2797
0
    int fd = fsp_get_pathref_fd(fsp);
2798
0
    struct sys_proc_fd_path_buf buf;
2799
2800
0
    result = chmod(sys_proc_fd_path(fd, &buf), mode);
2801
2802
0
    END_PROFILE_X(syscall_fchmod);
2803
0
    return result;
2804
0
  }
2805
2806
  /*
2807
   * This is no longer a handle based call.
2808
   */
2809
0
  result = chmod(fsp->fsp_name->base_name, mode);
2810
2811
0
  END_PROFILE_X(syscall_fchmod);
2812
0
  return result;
2813
0
}
2814
2815
static int vfswrap_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
2816
0
{
2817
0
#ifdef HAVE_FCHOWN
2818
0
  int result;
2819
2820
0
  START_PROFILE_X(SNUM(handle->conn), syscall_fchown);
2821
0
  if (!fsp->fsp_flags.is_pathref) {
2822
0
    result = fchown(fsp_get_io_fd(fsp), uid, gid);
2823
0
    END_PROFILE_X(syscall_fchown);
2824
0
    return result;
2825
0
  }
2826
2827
0
  if (fsp->fsp_flags.have_proc_fds) {
2828
0
    int fd = fsp_get_pathref_fd(fsp);
2829
0
    struct sys_proc_fd_path_buf buf;
2830
2831
0
    result = chown(sys_proc_fd_path(fd, &buf), uid, gid);
2832
2833
0
    END_PROFILE_X(syscall_fchown);
2834
0
    return result;
2835
0
  }
2836
2837
  /*
2838
   * This is no longer a handle based call.
2839
   */
2840
0
  result = chown(fsp->fsp_name->base_name, uid, gid);
2841
0
  END_PROFILE_X(syscall_fchown);
2842
0
  return result;
2843
#else
2844
  errno = ENOSYS;
2845
  return -1;
2846
#endif
2847
0
}
2848
2849
static int vfswrap_lchown(vfs_handle_struct *handle,
2850
      const struct smb_filename *smb_fname,
2851
      uid_t uid,
2852
      gid_t gid)
2853
0
{
2854
0
  int result;
2855
2856
0
  START_PROFILE_X(SNUM(handle->conn), syscall_lchown);
2857
0
  result = lchown(smb_fname->base_name, uid, gid);
2858
0
  END_PROFILE_X(syscall_lchown);
2859
0
  return result;
2860
0
}
2861
2862
static int vfswrap_chdir(vfs_handle_struct *handle,
2863
      const struct smb_filename *smb_fname)
2864
0
{
2865
0
  int result;
2866
2867
0
  START_PROFILE_X(SNUM(handle->conn), syscall_chdir);
2868
0
  result = chdir(smb_fname->base_name);
2869
0
  END_PROFILE_X(syscall_chdir);
2870
0
  return result;
2871
0
}
2872
2873
/*********************************************************************
2874
 nsec timestamp resolution call. Convert down to whatever the underlying
2875
 system will support.
2876
**********************************************************************/
2877
2878
static int vfswrap_fntimes(vfs_handle_struct *handle,
2879
         files_struct *fsp,
2880
         struct smb_file_time *ft)
2881
0
{
2882
0
  int result = -1;
2883
0
  struct timespec ts[2];
2884
0
  struct timespec *times = NULL;
2885
2886
0
  START_PROFILE_X(SNUM(handle->conn), syscall_fntimes);
2887
2888
0
  if (fsp_is_alternate_stream(fsp)) {
2889
0
    errno = ENOENT;
2890
0
    goto out;
2891
0
  }
2892
2893
0
  if (ft != NULL) {
2894
0
    if (is_omit_timespec(&ft->atime)) {
2895
0
      ft->atime = fsp->fsp_name->st.st_ex_atime;
2896
0
    }
2897
2898
0
    if (is_omit_timespec(&ft->mtime)) {
2899
0
      ft->mtime = fsp->fsp_name->st.st_ex_mtime;
2900
0
    }
2901
2902
0
    if (!is_omit_timespec(&ft->create_time)) {
2903
0
      set_create_timespec_ea(fsp,
2904
0
                 ft->create_time);
2905
0
    }
2906
2907
0
    if (timespec_equal(&ft->atime,
2908
0
           &fsp->fsp_name->st.st_ex_atime) &&
2909
0
        timespec_equal(&ft->mtime,
2910
0
           &fsp->fsp_name->st.st_ex_mtime))
2911
0
    {
2912
0
      result = 0;
2913
0
      goto out;
2914
0
    }
2915
2916
0
    ts[0] = ft->atime;
2917
0
    ts[1] = ft->mtime;
2918
0
    times = ts;
2919
0
  } else {
2920
0
    times = NULL;
2921
0
  }
2922
2923
0
  if (!fsp->fsp_flags.is_pathref) {
2924
0
    result = futimens(fsp_get_io_fd(fsp), times);
2925
0
    goto out;
2926
0
  }
2927
2928
0
  if (fsp->fsp_flags.have_proc_fds) {
2929
0
    int fd = fsp_get_pathref_fd(fsp);
2930
0
    struct sys_proc_fd_path_buf buf;
2931
2932
0
    result = utimensat(AT_FDCWD,
2933
0
           sys_proc_fd_path(fd, &buf),
2934
0
           times,
2935
0
           0);
2936
2937
0
    goto out;
2938
0
  }
2939
2940
  /*
2941
   * The fd is a pathref (opened with O_PATH) and there isn't fd to
2942
   * path translation mechanism. Fallback to path based call.
2943
   */
2944
0
  result = utimensat(AT_FDCWD, fsp->fsp_name->base_name, times, 0);
2945
2946
0
out:
2947
0
  END_PROFILE_X(syscall_fntimes);
2948
2949
0
  return result;
2950
0
}
2951
2952
2953
/*********************************************************************
2954
 A version of ftruncate that will write the space on disk if strict
2955
 allocate is set.
2956
**********************************************************************/
2957
2958
static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
2959
0
{
2960
0
  off_t space_to_write;
2961
0
  uint64_t space_avail;
2962
0
  uint64_t bsize,dfree,dsize;
2963
0
  int ret;
2964
0
  NTSTATUS status;
2965
0
  SMB_STRUCT_STAT *pst;
2966
0
  bool ok;
2967
2968
0
  ok = vfs_valid_allocation_range(len, 0);
2969
0
  if (!ok) {
2970
0
    errno = EINVAL;
2971
0
    return -1;
2972
0
  }
2973
2974
0
  status = vfs_stat_fsp(fsp);
2975
0
  if (!NT_STATUS_IS_OK(status)) {
2976
0
    return -1;
2977
0
  }
2978
0
  pst = &fsp->fsp_name->st;
2979
2980
0
#ifdef S_ISFIFO
2981
0
  if (S_ISFIFO(pst->st_ex_mode))
2982
0
    return 0;
2983
0
#endif
2984
2985
0
  if (pst->st_ex_size == len)
2986
0
    return 0;
2987
2988
  /* Shrink - just ftruncate. */
2989
0
  if (pst->st_ex_size > len)
2990
0
    return ftruncate(fsp_get_io_fd(fsp), len);
2991
2992
0
  space_to_write = len - pst->st_ex_size;
2993
2994
  /* for allocation try fallocate first. This can fail on some
2995
     platforms e.g. when the filesystem doesn't support it and no
2996
     emulation is being done by the libc (like on AIX with JFS1). In that
2997
     case we do our own emulation. fallocate implementations can
2998
     return ENOTSUP or EINVAL in cases like that. */
2999
0
  ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
3000
0
  if (ret == -1 && errno == ENOSPC) {
3001
0
    return -1;
3002
0
  }
3003
0
  if (ret == 0) {
3004
0
    return 0;
3005
0
  }
3006
0
  DBG_DEBUG("strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
3007
0
    "error %d. Falling back to slow manual allocation\n", errno);
3008
3009
  /* available disk space is enough or not? */
3010
0
  space_avail = get_dfree_info(fsp, &bsize, &dfree, &dsize);
3011
  /* space_avail is 1k blocks */
3012
0
  if (space_avail == (uint64_t)-1 ||
3013
0
      ((uint64_t)space_to_write/1024 > space_avail) ) {
3014
0
    errno = ENOSPC;
3015
0
    return -1;
3016
0
  }
3017
3018
  /* Write out the real space on disk. */
3019
0
  ret = vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
3020
0
  if (ret != 0) {
3021
0
    return -1;
3022
0
  }
3023
3024
0
  return 0;
3025
0
}
3026
3027
static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t len)
3028
0
{
3029
0
  int result = -1;
3030
0
  SMB_STRUCT_STAT *pst;
3031
0
  NTSTATUS status;
3032
0
  char c = 0;
3033
3034
0
  START_PROFILE_X(SNUM(handle->conn), syscall_ftruncate);
3035
3036
0
  if (lp_strict_allocate(SNUM(fsp->conn)) && !fsp->fsp_flags.is_sparse) {
3037
0
    result = strict_allocate_ftruncate(handle, fsp, len);
3038
0
    END_PROFILE_X(syscall_ftruncate);
3039
0
    return result;
3040
0
  }
3041
3042
  /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
3043
     ftruncate if the system supports it. Then I discovered that
3044
     you can have some filesystems that support ftruncate
3045
     expansion and some that don't! On Linux fat can't do
3046
     ftruncate extend but ext2 can. */
3047
3048
0
  result = ftruncate(fsp_get_io_fd(fsp), len);
3049
3050
  /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
3051
     extend a file with ftruncate. Provide alternate implementation
3052
     for this */
3053
3054
  /* Do an fstat to see if the file is longer than the requested
3055
     size in which case the ftruncate above should have
3056
     succeeded or shorter, in which case seek to len - 1 and
3057
     write 1 byte of zero */
3058
0
  status = vfs_stat_fsp(fsp);
3059
0
  if (!NT_STATUS_IS_OK(status)) {
3060
0
    goto done;
3061
0
  }
3062
3063
  /* We need to update the files_struct after successful ftruncate */
3064
0
  if (result == 0) {
3065
0
    goto done;
3066
0
  }
3067
3068
0
  pst = &fsp->fsp_name->st;
3069
3070
0
#ifdef S_ISFIFO
3071
0
  if (S_ISFIFO(pst->st_ex_mode)) {
3072
0
    result = 0;
3073
0
    goto done;
3074
0
  }
3075
0
#endif
3076
3077
0
  if (pst->st_ex_size == len) {
3078
0
    result = 0;
3079
0
    goto done;
3080
0
  }
3081
3082
0
  if (pst->st_ex_size > len) {
3083
    /* the ftruncate should have worked */
3084
0
    goto done;
3085
0
  }
3086
3087
0
  if (SMB_VFS_PWRITE(fsp, &c, 1, len-1)!=1) {
3088
0
    goto done;
3089
0
  }
3090
3091
0
  result = 0;
3092
3093
0
  done:
3094
3095
0
    END_PROFILE_X(syscall_ftruncate);
3096
0
    return result;
3097
0
}
3098
3099
static int vfswrap_fallocate(vfs_handle_struct *handle,
3100
      files_struct *fsp,
3101
      uint32_t mode,
3102
      off_t offset,
3103
      off_t len)
3104
0
{
3105
0
  int result;
3106
3107
0
  START_PROFILE_X(SNUM(handle->conn), syscall_fallocate);
3108
0
  if (mode == 0) {
3109
0
    result = sys_posix_fallocate(fsp_get_io_fd(fsp), offset, len);
3110
    /*
3111
     * posix_fallocate returns 0 on success, errno on error
3112
     * and doesn't set errno. Make it behave like fallocate()
3113
     * which returns -1, and sets errno on failure.
3114
     */
3115
0
    if (result != 0) {
3116
0
      errno = result;
3117
0
      result = -1;
3118
0
    }
3119
0
  } else {
3120
    /* sys_fallocate handles filtering of unsupported mode flags */
3121
0
    result = sys_fallocate(fsp_get_io_fd(fsp), mode, offset, len);
3122
0
  }
3123
0
  END_PROFILE_X(syscall_fallocate);
3124
0
  return result;
3125
0
}
3126
3127
static bool vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
3128
0
{
3129
0
  bool result;
3130
3131
0
  START_PROFILE_X(SNUM(handle->conn), syscall_fcntl_lock);
3132
3133
0
  if (fsp->fsp_flags.use_ofd_locks) {
3134
0
    op = map_process_lock_to_ofd_lock(op);
3135
0
  }
3136
3137
0
  result =  fcntl_lock(fsp_get_io_fd(fsp), op, offset, count, type);
3138
0
  END_PROFILE_X(syscall_fcntl_lock);
3139
0
  return result;
3140
0
}
3141
3142
static int vfswrap_filesystem_sharemode(vfs_handle_struct *handle,
3143
          files_struct *fsp,
3144
          uint32_t share_access,
3145
          uint32_t access_mask)
3146
0
{
3147
0
  errno = ENOTSUP;
3148
0
  return -1;
3149
0
}
3150
3151
static int vfswrap_fcntl(vfs_handle_struct *handle, files_struct *fsp, int cmd,
3152
       va_list cmd_arg)
3153
0
{
3154
0
  void *argp;
3155
0
  va_list dup_cmd_arg;
3156
0
  int result;
3157
0
  int val;
3158
3159
0
  START_PROFILE_X(SNUM(handle->conn), syscall_fcntl);
3160
3161
0
  va_copy(dup_cmd_arg, cmd_arg);
3162
3163
0
  switch(cmd) {
3164
0
  case F_SETLK:
3165
0
  case F_SETLKW:
3166
0
  case F_GETLK:
3167
0
#if defined(HAVE_OFD_LOCKS)
3168
0
  case F_OFD_SETLK:
3169
0
  case F_OFD_SETLKW:
3170
0
  case F_OFD_GETLK:
3171
0
#endif
3172
0
#if defined(HAVE_F_OWNER_EX)
3173
0
  case F_GETOWN_EX:
3174
0
  case F_SETOWN_EX:
3175
0
#endif
3176
0
#if defined(HAVE_RW_HINTS)
3177
0
  case F_GET_RW_HINT:
3178
0
  case F_SET_RW_HINT:
3179
0
  case F_GET_FILE_RW_HINT:
3180
0
  case F_SET_FILE_RW_HINT:
3181
0
#endif
3182
0
    argp = va_arg(dup_cmd_arg, void *);
3183
0
    result = sys_fcntl_ptr(fsp_get_io_fd(fsp), cmd, argp);
3184
0
    break;
3185
0
  default:
3186
0
    val = va_arg(dup_cmd_arg, int);
3187
0
    result = sys_fcntl_int(fsp_get_io_fd(fsp), cmd, val);
3188
0
  }
3189
3190
0
  va_end(dup_cmd_arg);
3191
3192
0
  END_PROFILE_X(syscall_fcntl);
3193
0
  return result;
3194
0
}
3195
3196
static bool vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
3197
0
{
3198
0
  bool result;
3199
0
  int op = F_GETLK;
3200
3201
0
  START_PROFILE_X(SNUM(handle->conn), syscall_fcntl_getlock);
3202
3203
0
  if (fsp->fsp_flags.use_ofd_locks) {
3204
0
    op = map_process_lock_to_ofd_lock(op);
3205
0
  }
3206
3207
0
  result = fcntl_getlock(fsp_get_io_fd(fsp), op, poffset, pcount, ptype, ppid);
3208
0
  END_PROFILE_X(syscall_fcntl_getlock);
3209
0
  return result;
3210
0
}
3211
3212
static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp,
3213
        int leasetype)
3214
0
{
3215
0
  int result = -1;
3216
3217
0
  START_PROFILE_X(SNUM(handle->conn), syscall_linux_setlease);
3218
3219
0
  SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3220
3221
0
#ifdef HAVE_KERNEL_OPLOCKS_LINUX
3222
0
  result = linux_setlease(fsp_get_io_fd(fsp), leasetype);
3223
#else
3224
  errno = ENOSYS;
3225
#endif
3226
0
  END_PROFILE_X(syscall_linux_setlease);
3227
0
  return result;
3228
0
}
3229
3230
static int vfswrap_symlinkat(vfs_handle_struct *handle,
3231
      const struct smb_filename *link_target,
3232
      struct files_struct *dirfsp,
3233
      const struct smb_filename *new_smb_fname)
3234
0
{
3235
0
  int result;
3236
3237
0
  START_PROFILE_X(SNUM(handle->conn), syscall_symlinkat);
3238
3239
0
  SMB_ASSERT(!is_named_stream(new_smb_fname));
3240
3241
0
  result = symlinkat(link_target->base_name,
3242
0
      fsp_get_pathref_fd(dirfsp),
3243
0
      new_smb_fname->base_name);
3244
0
  END_PROFILE_X(syscall_symlinkat);
3245
0
  return result;
3246
0
}
3247
3248
static int vfswrap_readlinkat(vfs_handle_struct *handle,
3249
      const struct files_struct *dirfsp,
3250
      const struct smb_filename *smb_fname,
3251
      char *buf,
3252
      size_t bufsiz)
3253
0
{
3254
0
  int result;
3255
3256
0
  START_PROFILE_X(SNUM(handle->conn), syscall_readlinkat);
3257
3258
0
  SMB_ASSERT(!is_named_stream(smb_fname));
3259
3260
0
  result = readlinkat(fsp_get_pathref_fd(dirfsp),
3261
0
      smb_fname->base_name,
3262
0
      buf,
3263
0
      bufsiz);
3264
3265
0
  END_PROFILE_X(syscall_readlinkat);
3266
0
  return result;
3267
0
}
3268
3269
static int vfswrap_linkat(vfs_handle_struct *handle,
3270
        files_struct *src_dirfsp,
3271
        const struct smb_filename *old_smb_fname,
3272
        files_struct *dst_dirfsp,
3273
        const struct smb_filename *new_smb_fname,
3274
        int flags)
3275
0
{
3276
0
  int result;
3277
3278
0
  START_PROFILE_X(SNUM(handle->conn), syscall_linkat);
3279
3280
0
  SMB_ASSERT(!is_named_stream(old_smb_fname));
3281
0
  SMB_ASSERT(!is_named_stream(new_smb_fname));
3282
3283
0
  result = linkat(fsp_get_pathref_fd(src_dirfsp),
3284
0
      old_smb_fname->base_name,
3285
0
      fsp_get_pathref_fd(dst_dirfsp),
3286
0
      new_smb_fname->base_name,
3287
0
      flags);
3288
3289
0
  END_PROFILE_X(syscall_linkat);
3290
0
  return result;
3291
0
}
3292
3293
static int vfswrap_mknodat(vfs_handle_struct *handle,
3294
      files_struct *dirfsp,
3295
      const struct smb_filename *smb_fname,
3296
      mode_t mode,
3297
      SMB_DEV_T dev)
3298
0
{
3299
0
  int result;
3300
3301
0
  START_PROFILE_X(SNUM(handle->conn), syscall_mknodat);
3302
3303
0
  SMB_ASSERT(!is_named_stream(smb_fname));
3304
3305
0
  result = sys_mknodat(fsp_get_pathref_fd(dirfsp),
3306
0
      smb_fname->base_name,
3307
0
      mode,
3308
0
      dev);
3309
3310
0
  END_PROFILE_X(syscall_mknodat);
3311
0
  return result;
3312
0
}
3313
3314
static struct smb_filename *vfswrap_realpath(vfs_handle_struct *handle,
3315
      TALLOC_CTX *ctx,
3316
      const struct smb_filename *smb_fname)
3317
0
{
3318
0
  char *result;
3319
0
  struct smb_filename *result_fname = NULL;
3320
3321
0
  START_PROFILE_X(SNUM(handle->conn), syscall_realpath);
3322
0
  result = sys_realpath(smb_fname->base_name);
3323
0
  END_PROFILE_X(syscall_realpath);
3324
0
  if (result) {
3325
0
    result_fname = cp_smb_basename(ctx, result);
3326
0
    SAFE_FREE(result);
3327
0
  }
3328
0
  return result_fname;
3329
0
}
3330
3331
static int vfswrap_fchflags(vfs_handle_struct *handle,
3332
      struct files_struct *fsp,
3333
      unsigned int flags)
3334
0
{
3335
#ifdef HAVE_FCHFLAGS
3336
  int fd = fsp_get_pathref_fd(fsp);
3337
3338
  SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3339
3340
  if (!fsp->fsp_flags.is_pathref) {
3341
    return fchflags(fd, flags);
3342
  }
3343
3344
  if (fsp->fsp_flags.have_proc_fds) {
3345
    struct sys_proc_fd_path_buf buf;
3346
3347
    return chflags(sys_proc_fd_path(fd, &buf), flags);
3348
  }
3349
3350
  /*
3351
   * This is no longer a handle based call.
3352
   */
3353
  return chflags(fsp->fsp_name->base_name, flags);
3354
#else
3355
0
  errno = ENOSYS;
3356
0
  return -1;
3357
0
#endif
3358
0
}
3359
3360
static struct file_id vfswrap_file_id_create(struct vfs_handle_struct *handle,
3361
               const SMB_STRUCT_STAT *sbuf)
3362
0
{
3363
0
  struct file_id key;
3364
3365
  /* the ZERO_STRUCT ensures padding doesn't break using the key as a
3366
   * blob */
3367
0
  ZERO_STRUCT(key);
3368
3369
0
  key.devid = sbuf->st_ex_dev;
3370
0
  key.inode = sbuf->st_ex_ino;
3371
  /* key.extid is unused by default. */
3372
3373
0
  return key;
3374
0
}
3375
3376
static uint64_t vfswrap_fs_file_id(struct vfs_handle_struct *handle,
3377
           const SMB_STRUCT_STAT *psbuf)
3378
0
{
3379
0
  uint64_t file_id;
3380
3381
0
  if (handle->conn->base_share_dev == psbuf->st_ex_dev) {
3382
0
    return (uint64_t)psbuf->st_ex_ino;
3383
0
  }
3384
3385
  /* FileIDLow */
3386
0
  file_id = ((psbuf->st_ex_ino) & UINT32_MAX);
3387
3388
  /* FileIDHigh */
3389
0
  file_id |= ((uint64_t)((psbuf->st_ex_dev) & UINT32_MAX)) << 32;
3390
3391
0
  return file_id;
3392
0
}
3393
3394
static NTSTATUS vfswrap_fstreaminfo(vfs_handle_struct *handle,
3395
           struct files_struct *fsp,
3396
           TALLOC_CTX *mem_ctx,
3397
           unsigned int *pnum_streams,
3398
           struct stream_struct **pstreams)
3399
0
{
3400
0
  struct stream_struct *tmp_streams = NULL;
3401
0
  unsigned int num_streams = *pnum_streams;
3402
0
  struct stream_struct *streams = *pstreams;
3403
0
  NTSTATUS status;
3404
3405
0
  SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3406
3407
0
  if (fsp->fsp_flags.is_directory) {
3408
    /*
3409
     * No default streams on directories
3410
     */
3411
0
    goto done;
3412
0
  }
3413
0
  status = vfs_stat_fsp(fsp);
3414
0
  if (!NT_STATUS_IS_OK(status)) {
3415
0
    return status;
3416
0
  }
3417
3418
0
  if (num_streams + 1 < 1) {
3419
    /* Integer wrap. */
3420
0
    return NT_STATUS_INVALID_PARAMETER;
3421
0
  }
3422
3423
0
  tmp_streams = talloc_realloc(mem_ctx,
3424
0
          streams,
3425
0
          struct stream_struct,
3426
0
          num_streams + 1);
3427
0
  if (tmp_streams == NULL) {
3428
0
    return NT_STATUS_NO_MEMORY;
3429
0
  }
3430
0
  tmp_streams[num_streams].name = talloc_strdup(tmp_streams, "::$DATA");
3431
0
  if (tmp_streams[num_streams].name == NULL) {
3432
0
    return NT_STATUS_NO_MEMORY;
3433
0
  }
3434
0
  tmp_streams[num_streams].size = fsp->fsp_name->st.st_ex_size;
3435
0
  tmp_streams[num_streams].alloc_size = SMB_VFS_GET_ALLOC_SIZE(
3436
0
            handle->conn,
3437
0
            fsp,
3438
0
            &fsp->fsp_name->st);
3439
0
  num_streams += 1;
3440
3441
0
  *pnum_streams = num_streams;
3442
0
  *pstreams = tmp_streams;
3443
0
 done:
3444
0
  return NT_STATUS_OK;
3445
0
}
3446
3447
static NTSTATUS vfswrap_get_real_filename_at(
3448
  struct vfs_handle_struct *handle,
3449
  struct files_struct *dirfsp,
3450
  const char *name,
3451
  TALLOC_CTX *mem_ctx,
3452
  char **found_name)
3453
0
{
3454
  /*
3455
   * Don't fall back to get_real_filename so callers can differentiate
3456
   * between a full directory scan and an actual case-insensitive stat.
3457
   */
3458
0
  return NT_STATUS_NOT_SUPPORTED;
3459
0
}
3460
3461
static NTSTATUS vfswrap_brl_lock_windows(struct vfs_handle_struct *handle,
3462
           struct byte_range_lock *br_lck,
3463
           struct lock_struct *plock)
3464
0
{
3465
0
  SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3466
3467
  /* Note: blr is not used in the default implementation. */
3468
0
  return brl_lock_windows_default(br_lck, plock);
3469
0
}
3470
3471
static bool vfswrap_brl_unlock_windows(struct vfs_handle_struct *handle,
3472
               struct byte_range_lock *br_lck,
3473
                     const struct lock_struct *plock)
3474
0
{
3475
0
  SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
3476
3477
0
  return brl_unlock_windows_default(br_lck, plock);
3478
0
}
3479
3480
static bool vfswrap_strict_lock_check(struct vfs_handle_struct *handle,
3481
              files_struct *fsp,
3482
              struct lock_struct *plock)
3483
0
{
3484
0
  SMB_ASSERT(plock->lock_type == READ_LOCK ||
3485
0
      plock->lock_type == WRITE_LOCK);
3486
3487
0
  return strict_lock_check_default(fsp, plock);
3488
0
}
3489
3490
/* NT ACL operations. */
3491
3492
static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle,
3493
            files_struct *fsp,
3494
            uint32_t security_info,
3495
            TALLOC_CTX *mem_ctx,
3496
            struct security_descriptor **ppdesc)
3497
0
{
3498
0
  NTSTATUS result;
3499
3500
0
  START_PROFILE_X(SNUM(handle->conn), fget_nt_acl);
3501
3502
0
  SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3503
3504
0
  result = posix_fget_nt_acl(fsp, security_info,
3505
0
           mem_ctx, ppdesc);
3506
0
  END_PROFILE_X(fget_nt_acl);
3507
0
  return result;
3508
0
}
3509
3510
static NTSTATUS vfswrap_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32_t security_info_sent, const struct security_descriptor *psd)
3511
0
{
3512
0
  NTSTATUS result;
3513
3514
0
  START_PROFILE_X(SNUM(handle->conn), fset_nt_acl);
3515
3516
0
  SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3517
3518
0
  result = set_nt_acl(fsp, security_info_sent, psd);
3519
0
  END_PROFILE_X(fset_nt_acl);
3520
0
  return result;
3521
0
}
3522
3523
static SMB_ACL_T vfswrap_sys_acl_get_fd(vfs_handle_struct *handle,
3524
          files_struct *fsp,
3525
          SMB_ACL_TYPE_T type,
3526
          TALLOC_CTX *mem_ctx)
3527
0
{
3528
0
  SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3529
3530
0
  return sys_acl_get_fd(handle, fsp, type, mem_ctx);
3531
0
}
3532
3533
static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle,
3534
          files_struct *fsp,
3535
          SMB_ACL_TYPE_T type,
3536
          SMB_ACL_T theacl)
3537
0
{
3538
0
  SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3539
3540
0
  return sys_acl_set_fd(handle, fsp, type, theacl);
3541
0
}
3542
3543
static int vfswrap_sys_acl_delete_def_fd(vfs_handle_struct *handle,
3544
           files_struct *fsp)
3545
0
{
3546
0
  SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3547
3548
0
  return sys_acl_delete_def_fd(handle, fsp);
3549
0
}
3550
3551
/****************************************************************
3552
 Extended attribute operations.
3553
*****************************************************************/
3554
3555
static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle,
3556
         struct files_struct *fsp,
3557
         const char *name,
3558
         void *value,
3559
         size_t size)
3560
0
{
3561
0
  int fd = fsp_get_pathref_fd(fsp);
3562
0
  ssize_t res = -1;
3563
3564
0
  START_PROFILE_X(SNUM(handle->conn), syscall_fgetxattr);
3565
3566
0
  SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3567
3568
0
  if (!fsp->fsp_flags.is_pathref) {
3569
0
    res = fgetxattr(fd, name, value, size);
3570
0
    goto out;
3571
0
  }
3572
3573
0
  if (fsp->fsp_flags.have_proc_fds) {
3574
0
    struct sys_proc_fd_path_buf buf;
3575
3576
0
    res = getxattr(sys_proc_fd_path(fd, &buf), name, value, size);
3577
0
    goto out;
3578
0
  }
3579
3580
  /*
3581
   * This is no longer a handle based call.
3582
   */
3583
0
  res = getxattr(fsp->fsp_name->base_name, name, value, size);
3584
0
out:
3585
0
  END_PROFILE_X(syscall_fgetxattr);
3586
0
  return res;
3587
0
}
3588
3589
struct vfswrap_getxattrat_state {
3590
  struct vfs_pthreadpool_job_state job_state;
3591
3592
  const char *xattr_name;
3593
  uint8_t *xattr_value;
3594
  ssize_t xattr_size;
3595
};
3596
3597
static int vfswrap_getxattrat_state_destructor(
3598
    struct vfswrap_getxattrat_state *state)
3599
0
{
3600
0
  return -1;
3601
0
}
3602
3603
/*  Check if there are enough threads available
3604
 *  to run asynchronous jobs and if the current
3605
 *  platform provides per-thread credentials.
3606
 */
3607
bool vfswrap_check_async_with_thread_creds(struct pthreadpool_tevent *pool)
3608
0
{
3609
0
  size_t max_threads = 0;
3610
0
  bool have_per_thread_cwd = false;
3611
0
  bool have_per_thread_creds = false;
3612
0
  bool do_async = false;
3613
3614
0
  max_threads = pthreadpool_tevent_max_threads(pool);
3615
0
  if (max_threads >= 1) {
3616
    /*
3617
    * We need a non sync threadpool!
3618
    */
3619
0
    have_per_thread_cwd = per_thread_cwd_supported();
3620
0
  }
3621
0
#ifdef HAVE_LINUX_THREAD_CREDENTIALS
3622
0
  have_per_thread_creds = true;
3623
0
#endif
3624
0
  if (have_per_thread_cwd && have_per_thread_creds) {
3625
0
    do_async = true;
3626
0
  }
3627
3628
0
  return do_async;
3629
0
}
3630
3631
static void vfswrap_getxattrat_do_sync(struct tevent_req *req);
3632
static void vfswrap_getxattrat_do_async(void *private_data);
3633
static void vfswrap_getxattrat_done(struct tevent_req *subreq);
3634
3635
static struct tevent_req *vfswrap_getxattrat_send(
3636
      TALLOC_CTX *mem_ctx,
3637
      struct tevent_context *ev,
3638
      struct vfs_handle_struct *handle,
3639
      files_struct *dir_fsp,
3640
      const struct smb_filename *smb_fname,
3641
      const char *xattr_name,
3642
      size_t alloc_hint)
3643
0
{
3644
0
  struct tevent_req *req = NULL;
3645
0
  struct tevent_req *subreq = NULL;
3646
0
  struct vfswrap_getxattrat_state *state = NULL;
3647
0
  bool do_async = false;
3648
3649
0
  SMB_ASSERT(!is_named_stream(smb_fname));
3650
3651
0
  req = tevent_req_create(mem_ctx, &state,
3652
0
        struct vfswrap_getxattrat_state);
3653
0
  if (req == NULL) {
3654
0
    return NULL;
3655
0
  }
3656
0
  *state = (struct vfswrap_getxattrat_state) {
3657
0
    .job_state.ev = ev,
3658
0
    .job_state.handle = handle,
3659
0
    .job_state.dir_fsp = dir_fsp,
3660
0
    .job_state.smb_fname = smb_fname,
3661
0
  };
3662
3663
0
  do_async = vfswrap_check_async_with_thread_creds(
3664
0
    dir_fsp->conn->sconn->pool);
3665
3666
0
  SMBPROFILE_BYTES_ASYNC_START_X(SNUM(handle->conn),
3667
0
               syscall_asys_getxattrat,
3668
0
               state->job_state.profile_bytes,
3669
0
               state->job_state.profile_bytes_x,
3670
0
               0);
3671
3672
0
  if (fsp_get_pathref_fd(dir_fsp) == -1) {
3673
0
    DBG_ERR("Need a valid directory fd\n");
3674
0
    tevent_req_error(req, EINVAL);
3675
0
    return tevent_req_post(req, ev);
3676
0
  }
3677
3678
0
  if (alloc_hint > 0) {
3679
0
    state->xattr_value = talloc_zero_array(state,
3680
0
                   uint8_t,
3681
0
                   alloc_hint);
3682
0
    if (tevent_req_nomem(state->xattr_value, req)) {
3683
0
      return tevent_req_post(req, ev);
3684
0
    }
3685
0
  }
3686
3687
0
  if (!do_async) {
3688
0
    vfswrap_getxattrat_do_sync(req);
3689
0
    return tevent_req_post(req, ev);
3690
0
  }
3691
3692
  /*
3693
   * Now allocate all parameters from a memory context that won't go away
3694
   * no matter what. These parameters will get used in threads and we
3695
   * can't reliably cancel threads, so all buffers passed to the threads
3696
   * must not be freed before all referencing threads terminate.
3697
   */
3698
3699
0
  state->job_state.name = talloc_strdup(state, smb_fname->base_name);
3700
0
  if (tevent_req_nomem(state->job_state.name, req)) {
3701
0
    return tevent_req_post(req, ev);
3702
0
  }
3703
3704
0
  state->xattr_name = talloc_strdup(state, xattr_name);
3705
0
  if (tevent_req_nomem(state->xattr_name, req)) {
3706
0
    return tevent_req_post(req, ev);
3707
0
  }
3708
3709
  /*
3710
   * This is a hot codepath so at first glance one might think we should
3711
   * somehow optimize away the token allocation and do a
3712
   * talloc_reference() or similar black magic instead. But due to the
3713
   * talloc_stackframe pool per SMB2 request this should be a simple copy
3714
   * without a malloc in most cases.
3715
   */
3716
0
  if (geteuid() == sec_initial_uid()) {
3717
0
    state->job_state.token = root_unix_token(state);
3718
0
  } else {
3719
0
    state->job_state.token = copy_unix_token(
3720
0
          state,
3721
0
          dir_fsp->conn->session_info->unix_token);
3722
0
  }
3723
3724
0
  if (tevent_req_nomem(state->job_state.token, req)) {
3725
0
    return tevent_req_post(req, ev);
3726
0
  }
3727
3728
0
  SMBPROFILE_BYTES_ASYNC_SET_IDLE_X(state->job_state.profile_bytes,
3729
0
            state->job_state.profile_bytes_x);
3730
3731
0
  subreq = pthreadpool_tevent_job_send(
3732
0
      state,
3733
0
      ev,
3734
0
      dir_fsp->conn->sconn->pool,
3735
0
      vfswrap_getxattrat_do_async,
3736
0
      state);
3737
0
  if (tevent_req_nomem(subreq, req)) {
3738
0
    return tevent_req_post(req, ev);
3739
0
  }
3740
0
  tevent_req_set_callback(subreq, vfswrap_getxattrat_done, req);
3741
3742
0
  talloc_set_destructor(state, vfswrap_getxattrat_state_destructor);
3743
3744
0
  return req;
3745
0
}
3746
3747
static void vfswrap_getxattrat_do_sync(struct tevent_req *req)
3748
0
{
3749
0
  struct vfswrap_getxattrat_state *state = tevent_req_data(
3750
0
    req, struct vfswrap_getxattrat_state);
3751
3752
0
  state->xattr_size = vfswrap_fgetxattr(state->job_state.handle,
3753
0
                state->job_state.smb_fname->fsp,
3754
0
                state->xattr_name,
3755
0
                state->xattr_value,
3756
0
                talloc_array_length(state->xattr_value));
3757
0
  if (state->xattr_size == -1) {
3758
0
    tevent_req_error(req, errno);
3759
0
    return;
3760
0
  }
3761
3762
0
  tevent_req_done(req);
3763
0
  return;
3764
0
}
3765
3766
static void vfswrap_getxattrat_do_async(void *private_data)
3767
0
{
3768
0
  struct vfswrap_getxattrat_state *state = talloc_get_type_abort(
3769
0
    private_data, struct vfswrap_getxattrat_state);
3770
0
  struct timespec start_time;
3771
0
  struct timespec end_time;
3772
0
  int ret;
3773
3774
0
  PROFILE_TIMESTAMP(&start_time);
3775
0
  SMBPROFILE_BYTES_ASYNC_SET_BUSY_X(state->job_state.profile_bytes,
3776
0
            state->job_state.profile_bytes_x);
3777
3778
  /*
3779
   * Here we simulate a getxattrat()
3780
   * call using fchdir();getxattr()
3781
   */
3782
3783
0
  per_thread_cwd_activate();
3784
3785
  /* Become the correct credential on this thread. */
3786
0
  ret = set_thread_credentials(state->job_state.token->uid,
3787
0
             state->job_state.token->gid,
3788
0
             (size_t)state->job_state.token->ngroups,
3789
0
             state->job_state.token->groups);
3790
0
  if (ret != 0) {
3791
0
    state->xattr_size = -1;
3792
0
    state->job_state.vfs_aio_state.error = errno;
3793
0
    goto end_profile;
3794
0
  }
3795
3796
0
  state->xattr_size = vfswrap_fgetxattr(state->job_state.handle,
3797
0
                state->job_state.smb_fname->fsp,
3798
0
                state->xattr_name,
3799
0
                state->xattr_value,
3800
0
                talloc_array_length(state->xattr_value));
3801
0
  if (state->xattr_size == -1) {
3802
0
    state->job_state.vfs_aio_state.error = errno;
3803
0
  }
3804
3805
0
end_profile:
3806
0
  PROFILE_TIMESTAMP(&end_time);
3807
0
  state->job_state.vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
3808
0
  SMBPROFILE_BYTES_ASYNC_SET_IDLE_X(state->job_state.profile_bytes,
3809
0
          state->job_state.profile_bytes_x);
3810
0
}
3811
3812
static void vfswrap_getxattrat_done(struct tevent_req *subreq)
3813
0
{
3814
0
  struct tevent_req *req = tevent_req_callback_data(
3815
0
    subreq, struct tevent_req);
3816
0
  struct vfswrap_getxattrat_state *state = tevent_req_data(
3817
0
    req, struct vfswrap_getxattrat_state);
3818
0
  int ret;
3819
0
  bool ok;
3820
3821
  /*
3822
   * Make sure we run as the user again
3823
   */
3824
0
  ok = change_to_user_and_service_by_fsp(state->job_state.dir_fsp);
3825
0
  SMB_ASSERT(ok);
3826
3827
0
  ret = pthreadpool_tevent_job_recv(subreq);
3828
0
  TALLOC_FREE(subreq);
3829
3830
0
  SMBPROFILE_BYTES_ASYNC_END_X(state->job_state.profile_bytes,
3831
0
        state->job_state.profile_bytes_x);
3832
0
  talloc_set_destructor(state, NULL);
3833
0
  if (ret != 0) {
3834
0
    if (ret != EAGAIN) {
3835
0
      tevent_req_error(req, ret);
3836
0
      return;
3837
0
    }
3838
    /*
3839
     * If we get EAGAIN from pthreadpool_tevent_job_recv() this
3840
     * means the lower level pthreadpool failed to create a new
3841
     * thread. Fallback to sync processing in that case to allow
3842
     * some progress for the client.
3843
     */
3844
0
    vfswrap_getxattrat_do_sync(req);
3845
0
    return;
3846
0
  }
3847
3848
0
  if (state->xattr_size == -1) {
3849
0
    tevent_req_error(req, state->job_state.vfs_aio_state.error);
3850
0
    return;
3851
0
  }
3852
3853
0
  if (state->xattr_value == NULL) {
3854
    /*
3855
     * The caller only wanted the size.
3856
     */
3857
0
    tevent_req_done(req);
3858
0
    return;
3859
0
  }
3860
3861
  /*
3862
   * shrink the buffer to the returned size.
3863
   * (can't fail). It means NULL if size is 0.
3864
   */
3865
0
  state->xattr_value = talloc_realloc(state,
3866
0
              state->xattr_value,
3867
0
              uint8_t,
3868
0
              state->xattr_size);
3869
3870
0
  tevent_req_done(req);
3871
0
}
3872
3873
static ssize_t vfswrap_getxattrat_recv(struct tevent_req *req,
3874
               struct vfs_aio_state *aio_state,
3875
               TALLOC_CTX *mem_ctx,
3876
               uint8_t **xattr_value)
3877
0
{
3878
0
  struct vfswrap_getxattrat_state *state = tevent_req_data(
3879
0
    req, struct vfswrap_getxattrat_state);
3880
0
  ssize_t xattr_size;
3881
3882
0
  if (tevent_req_is_unix_error(req, &aio_state->error)) {
3883
0
    tevent_req_received(req);
3884
0
    return -1;
3885
0
  }
3886
3887
0
  *aio_state = state->job_state.vfs_aio_state;
3888
0
  xattr_size = state->xattr_size;
3889
0
  if (xattr_value != NULL) {
3890
0
    *xattr_value = talloc_move(mem_ctx, &state->xattr_value);
3891
0
  }
3892
3893
0
  tevent_req_received(req);
3894
0
  return xattr_size;
3895
0
}
3896
3897
static ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
3898
0
{
3899
0
  int fd = fsp_get_pathref_fd(fsp);
3900
0
  ssize_t res = -1;
3901
3902
0
  START_PROFILE_X(SNUM(handle->conn), syscall_flistxattr);
3903
3904
0
  SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3905
3906
0
  if (!fsp->fsp_flags.is_pathref) {
3907
0
    res = flistxattr(fd, list, size);
3908
0
    goto out;
3909
0
  }
3910
3911
0
  if (fsp->fsp_flags.have_proc_fds) {
3912
0
    struct sys_proc_fd_path_buf buf;
3913
3914
0
    res = listxattr(sys_proc_fd_path(fd, &buf), list, size);
3915
0
    goto out;
3916
0
  }
3917
3918
  /*
3919
   * This is no longer a handle based call.
3920
   */
3921
0
  res = listxattr(fsp->fsp_name->base_name, list, size);
3922
0
out:
3923
0
  END_PROFILE_X(syscall_flistxattr);
3924
0
  return res;
3925
0
}
3926
3927
static int vfswrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
3928
0
{
3929
0
  int fd = fsp_get_pathref_fd(fsp);
3930
0
  int res = -1;
3931
3932
0
  START_PROFILE_X(SNUM(handle->conn), syscall_fremovexattr);
3933
3934
0
  SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3935
3936
0
  if (!fsp->fsp_flags.is_pathref) {
3937
0
    res = fremovexattr(fd, name);
3938
0
    goto out;
3939
0
  }
3940
3941
0
  if (fsp->fsp_flags.have_proc_fds) {
3942
0
    struct sys_proc_fd_path_buf buf;
3943
3944
0
    res = removexattr(sys_proc_fd_path(fd, &buf), name);
3945
0
    goto out;
3946
0
  }
3947
3948
  /*
3949
   * This is no longer a handle based call.
3950
   */
3951
0
  res = removexattr(fsp->fsp_name->base_name, name);
3952
0
out:
3953
0
  END_PROFILE_X(syscall_fremovexattr);
3954
0
  return res;
3955
0
}
3956
3957
static int vfswrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
3958
0
{
3959
0
  int fd = fsp_get_pathref_fd(fsp);
3960
0
  int res = -1;
3961
3962
0
  START_PROFILE_X(SNUM(handle->conn), syscall_fsetxattr);
3963
3964
0
  SMB_ASSERT(!fsp_is_alternate_stream(fsp));
3965
3966
0
  if (!fsp->fsp_flags.is_pathref) {
3967
0
    res = fsetxattr(fd, name, value, size, flags);
3968
0
    goto out;
3969
0
  }
3970
3971
0
  if (fsp->fsp_flags.have_proc_fds) {
3972
0
    struct sys_proc_fd_path_buf buf;
3973
3974
0
    res =  setxattr(sys_proc_fd_path(fd, &buf),
3975
0
        name,
3976
0
        value,
3977
0
        size,
3978
0
        flags);
3979
0
    goto out;
3980
0
  }
3981
3982
  /*
3983
   * This is no longer a handle based call.
3984
   */
3985
0
  res = setxattr(fsp->fsp_name->base_name, name, value, size, flags);
3986
0
out:
3987
0
  END_PROFILE_X(syscall_fsetxattr);
3988
0
  return res;
3989
0
}
3990
3991
static bool vfswrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
3992
0
{
3993
0
  return false;
3994
0
}
3995
3996
static bool vfswrap_is_offline(struct connection_struct *conn,
3997
             const struct smb_filename *fname)
3998
0
{
3999
0
  NTSTATUS status;
4000
0
  char *path;
4001
0
  bool offline = false;
4002
4003
0
        if (ISDOT(fname->base_name) || ISDOTDOT(fname->base_name)) {
4004
0
    return false;
4005
0
  }
4006
4007
0
  if (!lp_dmapi_support(SNUM(conn)) || !dmapi_have_session()) {
4008
0
#if defined(ENOTSUP)
4009
0
    errno = ENOTSUP;
4010
0
#endif
4011
0
    return false;
4012
0
  }
4013
4014
0
        status = get_full_smb_filename(talloc_tos(), fname, &path);
4015
0
        if (!NT_STATUS_IS_OK(status)) {
4016
0
                errno = map_errno_from_nt_status(status);
4017
0
                return false;
4018
0
        }
4019
4020
0
  offline = (dmapi_file_flags(path) & FILE_ATTRIBUTE_OFFLINE) != 0;
4021
4022
0
  TALLOC_FREE(path);
4023
4024
0
  return offline;
4025
0
}
4026
4027
static NTSTATUS vfswrap_durable_cookie(struct vfs_handle_struct *handle,
4028
               struct files_struct *fsp,
4029
               TALLOC_CTX *mem_ctx,
4030
               DATA_BLOB *cookie)
4031
0
{
4032
0
  return vfs_default_durable_cookie(fsp, mem_ctx, cookie);
4033
0
}
4034
4035
static NTSTATUS vfswrap_durable_disconnect(struct vfs_handle_struct *handle,
4036
             struct files_struct *fsp,
4037
             const DATA_BLOB old_cookie,
4038
             TALLOC_CTX *mem_ctx,
4039
             DATA_BLOB *new_cookie)
4040
0
{
4041
0
  return vfs_default_durable_disconnect(fsp, old_cookie, mem_ctx,
4042
0
                new_cookie);
4043
0
}
4044
4045
static NTSTATUS vfswrap_durable_reconnect(struct vfs_handle_struct *handle,
4046
            struct smb_request *smb1req,
4047
            struct smbXsrv_open *op,
4048
            const DATA_BLOB old_cookie,
4049
            TALLOC_CTX *mem_ctx,
4050
            struct files_struct **fsp,
4051
            DATA_BLOB *new_cookie)
4052
0
{
4053
0
  return vfs_default_durable_reconnect(handle->conn, smb1req, op,
4054
0
               old_cookie, mem_ctx,
4055
0
               fsp, new_cookie);
4056
0
}
4057
4058
static struct vfs_fn_pointers vfs_default_fns = {
4059
  /* Disk operations */
4060
4061
  .connect_fn = vfswrap_connect,
4062
  .disconnect_fn = vfswrap_disconnect,
4063
  .disk_free_fn = vfswrap_disk_free,
4064
  .get_quota_fn = vfswrap_get_quota,
4065
  .set_quota_fn = vfswrap_set_quota,
4066
  .get_shadow_copy_data_fn = vfswrap_get_shadow_copy_data,
4067
  .fstatvfs_fn = vfswrap_fstatvfs,
4068
  .fs_capabilities_fn = vfswrap_fs_capabilities,
4069
  .get_dfs_referrals_fn = vfswrap_get_dfs_referrals,
4070
  .create_dfs_pathat_fn = vfswrap_create_dfs_pathat,
4071
  .read_dfs_pathat_fn = vfswrap_read_dfs_pathat,
4072
  .snap_check_path_fn = vfswrap_snap_check_path,
4073
  .snap_create_fn = vfswrap_snap_create,
4074
  .snap_delete_fn = vfswrap_snap_delete,
4075
4076
  /* Directory operations */
4077
4078
  .fdopendir_fn = vfswrap_fdopendir,
4079
  .readdir_fn = vfswrap_readdir,
4080
  .freaddir_attr_fn = vfswrap_freaddir_attr,
4081
  .rewind_dir_fn = vfswrap_rewinddir,
4082
  .mkdirat_fn = vfswrap_mkdirat,
4083
  .closedir_fn = vfswrap_closedir,
4084
4085
  /* File operations */
4086
4087
  .openat_fn = vfswrap_openat,
4088
  .create_file_fn = vfswrap_create_file,
4089
  .close_fn = vfswrap_close,
4090
  .pread_fn = vfswrap_pread,
4091
  .pread_send_fn = vfswrap_pread_send,
4092
  .pread_recv_fn = vfswrap_pread_recv,
4093
  .pwrite_fn = vfswrap_pwrite,
4094
  .pwrite_send_fn = vfswrap_pwrite_send,
4095
  .pwrite_recv_fn = vfswrap_pwrite_recv,
4096
  .lseek_fn = vfswrap_lseek,
4097
  .sendfile_fn = vfswrap_sendfile,
4098
  .recvfile_fn = vfswrap_recvfile,
4099
  .renameat_fn = vfswrap_renameat,
4100
  .rename_stream_fn = vfswrap_rename_stream,
4101
  .fsync_send_fn = vfswrap_fsync_send,
4102
  .fsync_recv_fn = vfswrap_fsync_recv,
4103
  .stat_fn = vfswrap_stat,
4104
  .fstat_fn = vfswrap_fstat,
4105
  .lstat_fn = vfswrap_lstat,
4106
  .fstatat_fn = vfswrap_fstatat,
4107
  .get_alloc_size_fn = vfswrap_get_alloc_size,
4108
  .unlinkat_fn = vfswrap_unlinkat,
4109
  .fchmod_fn = vfswrap_fchmod,
4110
  .fchown_fn = vfswrap_fchown,
4111
  .lchown_fn = vfswrap_lchown,
4112
  .chdir_fn = vfswrap_chdir,
4113
  .fntimes_fn = vfswrap_fntimes,
4114
  .ftruncate_fn = vfswrap_ftruncate,
4115
  .fallocate_fn = vfswrap_fallocate,
4116
  .lock_fn = vfswrap_lock,
4117
  .filesystem_sharemode_fn = vfswrap_filesystem_sharemode,
4118
  .fcntl_fn = vfswrap_fcntl,
4119
  .linux_setlease_fn = vfswrap_linux_setlease,
4120
  .getlock_fn = vfswrap_getlock,
4121
  .symlinkat_fn = vfswrap_symlinkat,
4122
  .readlinkat_fn = vfswrap_readlinkat,
4123
  .linkat_fn = vfswrap_linkat,
4124
  .mknodat_fn = vfswrap_mknodat,
4125
  .realpath_fn = vfswrap_realpath,
4126
  .fchflags_fn = vfswrap_fchflags,
4127
  .file_id_create_fn = vfswrap_file_id_create,
4128
  .fs_file_id_fn = vfswrap_fs_file_id,
4129
  .fstreaminfo_fn = vfswrap_fstreaminfo,
4130
  .get_real_filename_at_fn = vfswrap_get_real_filename_at,
4131
  .brl_lock_windows_fn = vfswrap_brl_lock_windows,
4132
  .brl_unlock_windows_fn = vfswrap_brl_unlock_windows,
4133
  .strict_lock_check_fn = vfswrap_strict_lock_check,
4134
  .translate_name_fn = vfswrap_translate_name,
4135
  .parent_pathname_fn = vfswrap_parent_pathname,
4136
  .fsctl_fn = vfswrap_fsctl,
4137
  .fset_dos_attributes_fn = vfswrap_fset_dos_attributes,
4138
  .get_dos_attributes_send_fn = vfswrap_get_dos_attributes_send,
4139
  .get_dos_attributes_recv_fn = vfswrap_get_dos_attributes_recv,
4140
  .fget_dos_attributes_fn = vfswrap_fget_dos_attributes,
4141
  .offload_read_send_fn = vfswrap_offload_read_send,
4142
  .offload_read_recv_fn = vfswrap_offload_read_recv,
4143
  .offload_write_send_fn = vfswrap_offload_write_send,
4144
  .offload_write_recv_fn = vfswrap_offload_write_recv,
4145
  .fget_compression_fn = vfswrap_fget_compression,
4146
  .set_compression_fn = vfswrap_set_compression,
4147
4148
  /* NT ACL operations. */
4149
4150
  .fget_nt_acl_fn = vfswrap_fget_nt_acl,
4151
  .fset_nt_acl_fn = vfswrap_fset_nt_acl,
4152
4153
  /* POSIX ACL operations. */
4154
4155
  .sys_acl_get_fd_fn = vfswrap_sys_acl_get_fd,
4156
  .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
4157
  .sys_acl_set_fd_fn = vfswrap_sys_acl_set_fd,
4158
  .sys_acl_delete_def_fd_fn = vfswrap_sys_acl_delete_def_fd,
4159
4160
  /* EA operations. */
4161
  .getxattrat_send_fn = vfswrap_getxattrat_send,
4162
  .getxattrat_recv_fn = vfswrap_getxattrat_recv,
4163
  .fgetxattr_fn = vfswrap_fgetxattr,
4164
  .flistxattr_fn = vfswrap_flistxattr,
4165
  .fremovexattr_fn = vfswrap_fremovexattr,
4166
  .fsetxattr_fn = vfswrap_fsetxattr,
4167
4168
  /* aio operations */
4169
  .aio_force_fn = vfswrap_aio_force,
4170
4171
  /* durable handle operations */
4172
  .durable_cookie_fn = vfswrap_durable_cookie,
4173
  .durable_disconnect_fn = vfswrap_durable_disconnect,
4174
  .durable_reconnect_fn = vfswrap_durable_reconnect,
4175
};
4176
4177
static_decl_vfs;
4178
NTSTATUS vfs_default_init(TALLOC_CTX *ctx)
4179
0
{
4180
  /*
4181
   * Here we need to implement every call!
4182
   *
4183
   * As this is the end of the vfs module chain.
4184
   */
4185
0
  smb_vfs_assert_all_fns(&vfs_default_fns, DEFAULT_VFS_MODULE_NAME);
4186
0
  return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
4187
0
        DEFAULT_VFS_MODULE_NAME, &vfs_default_fns);
4188
0
}
4189
4190