2 Unix SMB/Netbios implementation.
4 VFS initialisation and support functions
5 Copyright (C) Tim Potter 1999
6 Copyright (C) Alexander Bokovoy 2002
7 Copyright (C) James Peach 2006
8 Copyright (C) Volker Lendecke 2009
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 This work was sponsored by Optifacio Software Services, Inc.
27 #include "system/filesys.h"
28 #include "smbd/smbd.h"
29 #include "smbd/globals.h"
30 #include "../lib/util/memcache.h"
31 #include "transfer_file.h"
33 #include "lib/util/tevent_unix.h"
34 #include "lib/util/tevent_ntstatus.h"
37 #define DBGC_CLASS DBGC_VFS
42 struct vfs_fsp_data *next;
43 struct vfs_handle_struct *owner;
44 void (*destroy)(void *p_data);
46 /* NOTE: This structure contains four pointers so that we can guarantee
47 * that the end of the structure is always both 4-byte and 8-byte aligned.
51 struct vfs_init_function_entry {
53 struct vfs_init_function_entry *prev, *next;
54 const struct vfs_fn_pointers *fns;
57 /****************************************************************************
58 maintain the list of available backends
59 ****************************************************************************/
61 static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name)
63 struct vfs_init_function_entry *entry = backends;
65 DEBUG(10, ("vfs_find_backend_entry called for %s\n", name));
68 if (strcmp(entry->name, name)==0) return entry;
75 NTSTATUS smb_register_vfs(int version, const char *name,
76 const struct vfs_fn_pointers *fns)
78 struct vfs_init_function_entry *entry = backends;
80 if ((version != SMB_VFS_INTERFACE_VERSION)) {
81 DEBUG(0, ("Failed to register vfs module.\n"
82 "The module was compiled against SMB_VFS_INTERFACE_VERSION %d,\n"
83 "current SMB_VFS_INTERFACE_VERSION is %d.\n"
84 "Please recompile against the current Samba Version!\n",
85 version, SMB_VFS_INTERFACE_VERSION));
86 return NT_STATUS_OBJECT_TYPE_MISMATCH;
89 if (!name || !name[0]) {
90 DEBUG(0,("smb_register_vfs() called with NULL pointer or empty name!\n"));
91 return NT_STATUS_INVALID_PARAMETER;
94 if (vfs_find_backend_entry(name)) {
95 DEBUG(0,("VFS module %s already loaded!\n", name));
96 return NT_STATUS_OBJECT_NAME_COLLISION;
99 entry = SMB_XMALLOC_P(struct vfs_init_function_entry);
100 entry->name = smb_xstrdup(name);
103 DLIST_ADD(backends, entry);
104 DEBUG(5, ("Successfully added vfs backend '%s'\n", name));
108 /****************************************************************************
109 initialise default vfs hooks
110 ****************************************************************************/
112 static void vfs_init_default(connection_struct *conn)
114 DEBUG(3, ("Initialising default vfs hooks\n"));
115 vfs_init_custom(conn, DEFAULT_VFS_MODULE_NAME);
118 /****************************************************************************
119 initialise custom vfs hooks
120 ****************************************************************************/
122 bool vfs_init_custom(connection_struct *conn, const char *vfs_object)
124 char *module_path = NULL;
125 char *module_name = NULL;
126 char *module_param = NULL, *p;
127 vfs_handle_struct *handle;
128 const struct vfs_init_function_entry *entry;
130 if (!conn||!vfs_object||!vfs_object[0]) {
131 DEBUG(0, ("vfs_init_custom() called with NULL pointer or "
132 "empty vfs_object!\n"));
137 static_init_vfs(NULL);
140 DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object));
142 module_path = smb_xstrdup(vfs_object);
144 p = strchr_m(module_path, ':');
149 trim_char(module_param, ' ', ' ');
152 trim_char(module_path, ' ', ' ');
154 module_name = smb_xstrdup(module_path);
156 if ((module_name[0] == '/') &&
157 (strcmp(module_path, DEFAULT_VFS_MODULE_NAME) != 0)) {
160 * Extract the module name from the path. Just use the base
161 * name of the last path component.
164 SAFE_FREE(module_name);
165 module_name = smb_xstrdup(strrchr_m(module_path, '/')+1);
167 p = strchr_m(module_name, '.');
174 /* First, try to load the module with the new module system */
175 entry = vfs_find_backend_entry(module_name);
179 DEBUG(5, ("vfs module [%s] not loaded - trying to load...\n",
182 status = smb_load_module("vfs", module_path);
183 if (!NT_STATUS_IS_OK(status)) {
184 DEBUG(0, ("error probing vfs module '%s': %s\n",
185 module_path, nt_errstr(status)));
189 entry = vfs_find_backend_entry(module_name);
191 DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
196 DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
198 handle = talloc_zero(conn, vfs_handle_struct);
200 DEBUG(0,("TALLOC_ZERO() failed!\n"));
204 handle->fns = entry->fns;
206 handle->param = talloc_strdup(conn, module_param);
208 DLIST_ADD(conn->vfs_handles, handle);
210 SAFE_FREE(module_path);
211 SAFE_FREE(module_name);
215 SAFE_FREE(module_path);
216 SAFE_FREE(module_name);
220 /*****************************************************************
221 Allow VFS modules to extend files_struct with VFS-specific state.
222 This will be ok for small numbers of extensions, but might need to
223 be refactored if it becomes more widely used.
224 ******************************************************************/
226 #define EXT_DATA_AREA(e) ((uint8_t *)(e) + sizeof(struct vfs_fsp_data))
228 void *vfs_add_fsp_extension_notype(vfs_handle_struct *handle,
229 files_struct *fsp, size_t ext_size,
230 void (*destroy_fn)(void *p_data))
232 struct vfs_fsp_data *ext;
235 /* Prevent VFS modules adding multiple extensions. */
236 if ((ext_data = vfs_fetch_fsp_extension(handle, fsp))) {
240 ext = (struct vfs_fsp_data *)TALLOC_ZERO(
241 handle->conn, sizeof(struct vfs_fsp_data) + ext_size);
247 ext->next = fsp->vfs_extension;
248 ext->destroy = destroy_fn;
249 fsp->vfs_extension = ext;
250 return EXT_DATA_AREA(ext);
253 void vfs_remove_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
255 struct vfs_fsp_data *curr;
256 struct vfs_fsp_data *prev;
258 for (curr = fsp->vfs_extension, prev = NULL;
260 prev = curr, curr = curr->next) {
261 if (curr->owner == handle) {
263 prev->next = curr->next;
265 fsp->vfs_extension = curr->next;
268 curr->destroy(EXT_DATA_AREA(curr));
276 void vfs_remove_all_fsp_extensions(files_struct *fsp)
278 struct vfs_fsp_data *curr;
279 struct vfs_fsp_data *next;
281 for (curr = fsp->vfs_extension; curr; curr = next) {
284 fsp->vfs_extension = next;
287 curr->destroy(EXT_DATA_AREA(curr));
293 void *vfs_memctx_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
295 struct vfs_fsp_data *head;
297 for (head = fsp->vfs_extension; head; head = head->next) {
298 if (head->owner == handle) {
306 void *vfs_fetch_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
308 struct vfs_fsp_data *head;
310 head = (struct vfs_fsp_data *)vfs_memctx_fsp_extension(handle, fsp);
312 return EXT_DATA_AREA(head);
321 * Ensure this module catches all VFS functions.
324 void smb_vfs_assert_all_fns(const struct vfs_fn_pointers* fns,
327 bool missing_fn = false;
329 const uintptr_t *end = (const uintptr_t *)(fns + 1);
331 for (idx = 0; ((const uintptr_t *)fns + idx) < end; idx++) {
332 if (*((const uintptr_t *)fns + idx) == 0) {
333 DBG_ERR("VFS function at index %d not implemented "
334 "in module %s\n", idx, module);
340 smb_panic("Required VFS function not implemented in module.\n");
344 void smb_vfs_assert_all_fns(const struct vfs_fn_pointers* fns,
350 /*****************************************************************
352 ******************************************************************/
354 bool smbd_vfs_init(connection_struct *conn)
356 const char **vfs_objects;
360 /* Normal share - initialise with disk access functions */
361 vfs_init_default(conn);
363 /* No need to load vfs modules for printer connections */
368 vfs_objects = lp_vfs_objects(SNUM(conn));
370 /* Override VFS functions if 'vfs object' was not specified*/
371 if (!vfs_objects || !vfs_objects[0])
374 for (i=0; vfs_objects[i] ;) {
378 for (j=i-1; j >= 0; j--) {
379 if (!vfs_init_custom(conn, vfs_objects[j])) {
380 DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects[j]));
387 /*******************************************************************
388 Check if a file exists in the vfs.
389 ********************************************************************/
391 NTSTATUS vfs_file_exist(connection_struct *conn, struct smb_filename *smb_fname)
393 /* Only return OK if stat was successful and S_ISREG */
394 if ((SMB_VFS_STAT(conn, smb_fname) != -1) &&
395 S_ISREG(smb_fname->st.st_ex_mode)) {
399 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
402 ssize_t vfs_pwrite_data(struct smb_request *req,
411 if (req && req->unread_bytes) {
412 int sockfd = req->xconn->transport.sock;
413 SMB_ASSERT(req->unread_bytes == N);
414 /* VFS_RECVFILE must drain the socket
415 * before returning. */
416 req->unread_bytes = 0;
418 * Leave the socket non-blocking and
419 * use SMB_VFS_RECVFILE. If it returns
420 * EAGAIN || EWOULDBLOCK temporarily set
421 * the socket blocking and retry
425 ret = SMB_VFS_RECVFILE(sockfd,
429 if (ret == 0 || (ret == -1 &&
431 errno == EWOULDBLOCK))) {
433 /* Ensure the socket is blocking. */
434 old_flags = fcntl(sockfd, F_GETFL, 0);
435 if (set_blocking(sockfd, true) == -1) {
438 ret = SMB_VFS_RECVFILE(sockfd,
442 if (fcntl(sockfd, F_SETFL, old_flags) == -1) {
449 return (ssize_t)total;
451 /* Any other error case. */
457 return (ssize_t)total;
461 ret = SMB_VFS_PWRITE(fsp, buffer + total, N - total,
471 return (ssize_t)total;
473 /****************************************************************************
474 An allocate file space call using the vfs interface.
475 Allocates space for a file from a filedescriptor.
476 Returns 0 on success, -1 on failure.
477 ****************************************************************************/
479 int vfs_allocate_file_space(files_struct *fsp, uint64_t len)
482 connection_struct *conn = fsp->conn;
483 uint64_t space_avail;
484 uint64_t bsize,dfree,dsize;
488 * Actually try and commit the space on disk....
491 DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n",
492 fsp_str_dbg(fsp), (double)len));
494 if (((off_t)len) < 0) {
495 DEBUG(0,("vfs_allocate_file_space: %s negative len "
496 "requested.\n", fsp_str_dbg(fsp)));
501 status = vfs_stat_fsp(fsp);
502 if (!NT_STATUS_IS_OK(status)) {
506 if (len == (uint64_t)fsp->fsp_name->st.st_ex_size)
509 if (len < (uint64_t)fsp->fsp_name->st.st_ex_size) {
510 /* Shrink - use ftruncate. */
512 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current "
513 "size %.0f\n", fsp_str_dbg(fsp),
514 (double)fsp->fsp_name->st.st_ex_size));
516 contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_ALLOC_SHRINK);
518 flush_write_cache(fsp, SAMBA_SIZECHANGE_FLUSH);
519 if ((ret = SMB_VFS_FTRUNCATE(fsp, (off_t)len)) != -1) {
520 set_filelen_write_cache(fsp, len);
523 contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_ALLOC_SHRINK);
528 /* Grow - we need to test if we have enough space. */
530 contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_ALLOC_GROW);
532 if (lp_strict_allocate(SNUM(fsp->conn))) {
533 /* See if we have a syscall that will allocate beyond
534 end-of-file without changing EOF. */
535 ret = SMB_VFS_FALLOCATE(fsp, VFS_FALLOCATE_FL_KEEP_SIZE,
541 contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_ALLOC_GROW);
544 /* We changed the allocation size on disk, but not
545 EOF - exactly as required. We're done ! */
549 if (ret == -1 && errno == ENOSPC) {
553 len -= fsp->fsp_name->st.st_ex_size;
554 len /= 1024; /* Len is now number of 1k blocks needed. */
556 get_dfree_info(conn, fsp->fsp_name, &bsize, &dfree, &dsize);
557 if (space_avail == (uint64_t)-1) {
561 DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, "
562 "needed blocks = %.0f, space avail = %.0f\n",
563 fsp_str_dbg(fsp), (double)fsp->fsp_name->st.st_ex_size, (double)len,
564 (double)space_avail));
566 if (len > space_avail) {
574 /****************************************************************************
575 A vfs set_filelen call.
576 set the length of a file from a filedescriptor.
577 Returns 0 on success, -1 on failure.
578 ****************************************************************************/
580 int vfs_set_filelen(files_struct *fsp, off_t len)
584 contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_SET_FILE_LEN);
586 DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n",
587 fsp_str_dbg(fsp), (double)len));
588 flush_write_cache(fsp, SAMBA_SIZECHANGE_FLUSH);
589 if ((ret = SMB_VFS_FTRUNCATE(fsp, len)) != -1) {
590 set_filelen_write_cache(fsp, len);
591 notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
592 FILE_NOTIFY_CHANGE_SIZE
593 | FILE_NOTIFY_CHANGE_ATTRIBUTES,
594 fsp->fsp_name->base_name);
597 contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_SET_FILE_LEN);
602 /****************************************************************************
603 A slow version of fallocate. Fallback code if SMB_VFS_FALLOCATE
604 fails. Needs to be outside of the default version of SMB_VFS_FALLOCATE
605 as this is also called from the default SMB_VFS_FTRUNCATE code.
606 Always extends the file size.
607 Returns 0 on success, -1 on failure.
608 ****************************************************************************/
610 #define SPARSE_BUF_WRITE_SIZE (32*1024)
612 int vfs_slow_fallocate(files_struct *fsp, off_t offset, off_t len)
618 sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE);
625 while (total < len) {
626 size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (len - total));
628 pwrite_ret = SMB_VFS_PWRITE(fsp, sparse_buf, curr_write_size, offset + total);
629 if (pwrite_ret == -1) {
630 int saved_errno = errno;
631 DEBUG(10,("vfs_slow_fallocate: SMB_VFS_PWRITE for file "
632 "%s failed with error %s\n",
633 fsp_str_dbg(fsp), strerror(saved_errno)));
643 /****************************************************************************
644 A vfs fill sparse call.
645 Writes zeros from the end of file to len, if len is greater than EOF.
646 Used only by strict_sync.
647 Returns 0 on success, -1 on failure.
648 ****************************************************************************/
650 int vfs_fill_sparse(files_struct *fsp, off_t len)
657 status = vfs_stat_fsp(fsp);
658 if (!NT_STATUS_IS_OK(status)) {
662 if (len <= fsp->fsp_name->st.st_ex_size) {
667 if (S_ISFIFO(fsp->fsp_name->st.st_ex_mode)) {
672 DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to "
673 "len %.0f (%.0f bytes)\n", fsp_str_dbg(fsp),
674 (double)fsp->fsp_name->st.st_ex_size, (double)len,
675 (double)(len - fsp->fsp_name->st.st_ex_size)));
677 contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_FILL_SPARSE);
679 flush_write_cache(fsp, SAMBA_SIZECHANGE_FLUSH);
681 offset = fsp->fsp_name->st.st_ex_size;
682 num_to_write = len - fsp->fsp_name->st.st_ex_size;
684 /* Only do this on non-stream file handles. */
685 if (fsp->base_fsp == NULL) {
686 /* for allocation try fallocate first. This can fail on some
687 * platforms e.g. when the filesystem doesn't support it and no
688 * emulation is being done by the libc (like on AIX with JFS1). In that
689 * case we do our own emulation. fallocate implementations can
690 * return ENOTSUP or EINVAL in cases like that. */
691 ret = SMB_VFS_FALLOCATE(fsp, 0, offset, num_to_write);
692 if (ret == -1 && errno == ENOSPC) {
698 DEBUG(10,("vfs_fill_sparse: SMB_VFS_FALLOCATE failed with "
699 "error %d. Falling back to slow manual allocation\n", ret));
702 ret = vfs_slow_fallocate(fsp, offset, num_to_write);
707 set_filelen_write_cache(fsp, len);
710 contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_FILL_SPARSE);
714 /****************************************************************************
715 Transfer some data (n bytes) between two file_struct's.
716 ****************************************************************************/
718 static ssize_t vfs_pread_fn(void *file, void *buf, size_t len, off_t offset)
720 struct files_struct *fsp = (struct files_struct *)file;
722 return SMB_VFS_PREAD(fsp, buf, len, offset);
725 static ssize_t vfs_pwrite_fn(void *file, const void *buf, size_t len, off_t offset)
727 struct files_struct *fsp = (struct files_struct *)file;
729 return SMB_VFS_PWRITE(fsp, buf, len, offset);
732 off_t vfs_transfer_file(files_struct *in, files_struct *out, off_t n)
734 return transfer_file_internal((void *)in, (void *)out, n,
735 vfs_pread_fn, vfs_pwrite_fn);
738 /*******************************************************************
739 A vfs_readdir wrapper which just returns the file name.
740 ********************************************************************/
742 const char *vfs_readdirname(connection_struct *conn, void *p,
743 SMB_STRUCT_STAT *sbuf, char **talloced)
745 struct dirent *ptr= NULL;
753 ptr = SMB_VFS_READDIR(conn, (DIR *)p, sbuf);
765 #ifdef HAVE_BROKEN_READDIR_NAME
766 /* using /usr/ucb/cc is BAD */
770 status = SMB_VFS_TRANSLATE_NAME(conn, dname, vfs_translate_to_windows,
771 talloc_tos(), &translated);
772 if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
776 *talloced = translated;
777 if (!NT_STATUS_IS_OK(status)) {
783 /*******************************************************************
784 A wrapper for vfs_chdir().
785 ********************************************************************/
787 int vfs_ChDir(connection_struct *conn, const struct smb_filename *smb_fname)
791 struct smb_filename *old_cwd = conn->cwd_fname;
794 LastDir = SMB_STRDUP("");
797 if (ISDOT(smb_fname->base_name)) {
801 if (*smb_fname->base_name == '/' &&
802 strcsequal(LastDir,smb_fname->base_name)) {
806 DEBUG(4,("vfs_ChDir to %s\n", smb_fname->base_name));
808 ret = SMB_VFS_CHDIR(conn, smb_fname);
814 * Always replace conn->cwd_fname. We
815 * don't know if it's been modified by
816 * VFS modules in the stack.
820 conn->cwd_fname = vfs_GetWd(conn, conn);
821 if (conn->cwd_fname == NULL) {
823 * vfs_GetWd() failed.
824 * We must be able to read cwd.
825 * Return to original directory
830 if (old_cwd == NULL) {
832 * Failed on the very first chdir()+getwd()
833 * for this connection. We can't
836 smb_panic("conn->cwd getwd failed\n");
840 /* Restore original conn->cwd_fname. */
841 conn->cwd_fname = old_cwd;
843 /* Return to the previous $cwd. */
844 ret = SMB_VFS_CHDIR(conn, conn->cwd_fname);
846 smb_panic("conn->cwd getwd failed\n");
851 /* And fail the chdir(). */
855 /* vfs_GetWd() succeeded. */
856 /* Replace global cache. */
858 LastDir = SMB_STRDUP(smb_fname->base_name);
860 DEBUG(4,("vfs_ChDir got %s\n", conn->cwd_fname->base_name));
862 TALLOC_FREE(old_cwd);
863 if (saved_errno != 0) {
869 /*******************************************************************
870 Return the absolute current directory path - given a UNIX pathname.
871 Note that this path is returned in DOS format, not UNIX
872 format. Note this can be called with conn == NULL.
873 ********************************************************************/
875 struct smb_filename *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn)
877 struct smb_filename *current_dir_fname = NULL;
879 struct smb_filename *smb_fname_dot = NULL;
880 struct smb_filename *smb_fname_full = NULL;
881 struct smb_filename *result = NULL;
883 if (!lp_getwd_cache()) {
887 smb_fname_dot = synthetic_smb_fname(ctx, ".", NULL, NULL, 0);
888 if (smb_fname_dot == NULL) {
893 if (SMB_VFS_STAT(conn, smb_fname_dot) == -1) {
895 * Known to fail for root: the directory may be NFS-mounted
896 * and exported with root_squash (so has no root access).
898 DEBUG(1,("vfs_GetWd: couldn't stat \".\" error %s "
899 "(NFS problem ?)\n", strerror(errno) ));
903 key = vfs_file_id_from_sbuf(conn, &smb_fname_dot->st);
905 smb_fname_full = (struct smb_filename *)memcache_lookup_talloc(
908 data_blob_const(&key, sizeof(key)));
910 if (smb_fname_full == NULL) {
914 if ((SMB_VFS_STAT(conn, smb_fname_full) == 0) &&
915 (smb_fname_dot->st.st_ex_dev == smb_fname_full->st.st_ex_dev) &&
916 (smb_fname_dot->st.st_ex_ino == smb_fname_full->st.st_ex_ino) &&
917 (S_ISDIR(smb_fname_dot->st.st_ex_mode))) {
920 * Note: smb_fname_full is owned by smbd_memcache()
921 * so we must make a copy to return.
923 result = cp_smb_filename(ctx, smb_fname_full);
924 if (result == NULL) {
933 * We don't have the information to hand so rely on traditional
934 * methods. The very slow getcwd, which spawns a process on some
935 * systems, or the not quite so bad getwd.
938 current_dir_fname = SMB_VFS_GETWD(conn, ctx);
939 if (current_dir_fname == NULL) {
940 DEBUG(0, ("vfs_GetWd: SMB_VFS_GETWD call failed: %s\n",
945 if (lp_getwd_cache() && VALID_STAT(smb_fname_dot->st)) {
946 key = vfs_file_id_from_sbuf(conn, &smb_fname_dot->st);
949 * smbd_memcache() will own current_dir_fname after the
950 * memcache_add_talloc call, so we must make
951 * a copy on ctx to return.
953 result = cp_smb_filename(ctx, current_dir_fname);
954 if (result == NULL) {
959 * Ensure the memory going into the cache
960 * doesn't have a destructor so it can be
963 talloc_set_destructor(current_dir_fname, NULL);
965 memcache_add_talloc(smbd_memcache(),
967 data_blob_const(&key, sizeof(key)),
969 /* current_dir_fname is now == NULL here. */
971 /* current_dir_fname is already allocated on ctx. */
972 result = current_dir_fname;
976 TALLOC_FREE(smb_fname_dot);
978 * Don't free current_dir_fname here. It's either been moved
979 * to the memcache or is being returned in result.
984 /*******************************************************************
985 Reduce a file name, removing .. elements and checking that
986 it is below dir in the heirachy. This uses realpath.
987 This function must run as root, and will return names
988 and valid stat structs that can be checked on open.
989 ********************************************************************/
991 NTSTATUS check_reduced_name_with_privilege(connection_struct *conn,
992 const struct smb_filename *smb_fname,
993 struct smb_request *smbreq)
996 TALLOC_CTX *ctx = talloc_tos();
997 const char *conn_rootdir;
999 char *dir_name = NULL;
1000 char *resolved_name = NULL;
1001 const char *last_component = NULL;
1002 struct smb_filename *resolved_fname = NULL;
1003 struct smb_filename *saved_dir_fname = NULL;
1004 struct smb_filename *smb_fname_cwd = NULL;
1005 struct privilege_paths *priv_paths = NULL;
1008 DEBUG(3,("check_reduced_name_with_privilege [%s] [%s]\n",
1009 smb_fname->base_name,
1010 conn->connectpath));
1013 priv_paths = talloc_zero(smbreq, struct privilege_paths);
1015 status = NT_STATUS_NO_MEMORY;
1019 if (!parent_dirname(ctx, smb_fname->base_name,
1020 &dir_name, &last_component)) {
1021 status = NT_STATUS_NO_MEMORY;
1025 priv_paths->parent_name.base_name = talloc_strdup(priv_paths, dir_name);
1026 priv_paths->file_name.base_name = talloc_strdup(priv_paths, last_component);
1028 if (priv_paths->parent_name.base_name == NULL ||
1029 priv_paths->file_name.base_name == NULL) {
1030 status = NT_STATUS_NO_MEMORY;
1034 if (SMB_VFS_STAT(conn, &priv_paths->parent_name) != 0) {
1035 status = map_nt_error_from_unix(errno);
1038 /* Remember where we were. */
1039 saved_dir_fname = vfs_GetWd(ctx, conn);
1040 if (!saved_dir_fname) {
1041 status = map_nt_error_from_unix(errno);
1045 if (vfs_ChDir(conn, &priv_paths->parent_name) == -1) {
1046 status = map_nt_error_from_unix(errno);
1050 smb_fname_cwd = synthetic_smb_fname(talloc_tos(), ".", NULL, NULL, 0);
1051 if (smb_fname_cwd == NULL) {
1052 status = NT_STATUS_NO_MEMORY;
1056 /* Get the absolute path of the parent directory. */
1057 resolved_fname = SMB_VFS_REALPATH(conn, ctx, smb_fname_cwd);
1058 if (resolved_fname == NULL) {
1059 status = map_nt_error_from_unix(errno);
1062 resolved_name = resolved_fname->base_name;
1064 if (*resolved_name != '/') {
1065 DEBUG(0,("check_reduced_name_with_privilege: realpath "
1066 "doesn't return absolute paths !\n"));
1067 status = NT_STATUS_OBJECT_NAME_INVALID;
1071 DEBUG(10,("check_reduced_name_with_privilege: realpath [%s] -> [%s]\n",
1072 priv_paths->parent_name.base_name,
1075 /* Now check the stat value is the same. */
1076 if (SMB_VFS_LSTAT(conn, smb_fname_cwd) != 0) {
1077 status = map_nt_error_from_unix(errno);
1081 /* Ensure we're pointing at the same place. */
1082 if (!check_same_stat(&smb_fname_cwd->st, &priv_paths->parent_name.st)) {
1083 DEBUG(0,("check_reduced_name_with_privilege: "
1084 "device/inode/uid/gid on directory %s changed. "
1085 "Denying access !\n",
1086 priv_paths->parent_name.base_name));
1087 status = NT_STATUS_ACCESS_DENIED;
1091 /* Ensure we're below the connect path. */
1093 conn_rootdir = SMB_VFS_CONNECTPATH(conn, smb_fname);
1094 if (conn_rootdir == NULL) {
1095 DEBUG(2, ("check_reduced_name_with_privilege: Could not get "
1097 status = NT_STATUS_ACCESS_DENIED;
1101 rootdir_len = strlen(conn_rootdir);
1104 * In the case of rootdir_len == 1, we know that conn_rootdir is
1105 * "/", and we also know that resolved_name starts with a slash.
1106 * So, in this corner case, resolved_name is automatically a
1107 * sub-directory of the conn_rootdir. Thus we can skip the string
1108 * comparison and the next character checks (which are even
1109 * wrong in this case).
1111 if (rootdir_len != 1) {
1114 matched = (strncmp(conn_rootdir, resolved_name,
1117 if (!matched || (resolved_name[rootdir_len] != '/' &&
1118 resolved_name[rootdir_len] != '\0')) {
1119 DEBUG(2, ("check_reduced_name_with_privilege: Bad "
1120 "access attempt: %s is a symlink outside the "
1123 DEBUGADD(2, ("conn_rootdir =%s\n", conn_rootdir));
1124 DEBUGADD(2, ("resolved_name=%s\n", resolved_name));
1125 status = NT_STATUS_ACCESS_DENIED;
1130 /* Now ensure that the last component either doesn't
1131 exist, or is *NOT* a symlink. */
1133 ret = SMB_VFS_LSTAT(conn, &priv_paths->file_name);
1135 /* Errno must be ENOENT for this be ok. */
1136 if (errno != ENOENT) {
1137 status = map_nt_error_from_unix(errno);
1138 DEBUG(2, ("check_reduced_name_with_privilege: "
1139 "LSTAT on %s failed with %s\n",
1140 priv_paths->file_name.base_name,
1141 nt_errstr(status)));
1146 if (VALID_STAT(priv_paths->file_name.st) &&
1147 S_ISLNK(priv_paths->file_name.st.st_ex_mode)) {
1148 DEBUG(2, ("check_reduced_name_with_privilege: "
1149 "Last component %s is a symlink. Denying"
1151 priv_paths->file_name.base_name));
1152 status = NT_STATUS_ACCESS_DENIED;
1156 smbreq->priv_paths = priv_paths;
1157 status = NT_STATUS_OK;
1161 if (saved_dir_fname != NULL) {
1162 vfs_ChDir(conn, saved_dir_fname);
1163 TALLOC_FREE(saved_dir_fname);
1165 TALLOC_FREE(resolved_fname);
1166 if (!NT_STATUS_IS_OK(status)) {
1167 TALLOC_FREE(priv_paths);
1169 TALLOC_FREE(dir_name);
1173 /*******************************************************************
1174 Reduce a file name, removing .. elements and checking that
1175 it is below dir in the heirachy. This uses realpath.
1177 If cwd_name == NULL then fname is a client given path relative
1178 to the root path of the share.
1180 If cwd_name != NULL then fname is a client given path relative
1181 to cwd_name. cwd_name is relative to the root path of the share.
1182 ********************************************************************/
1184 NTSTATUS check_reduced_name(connection_struct *conn,
1185 const struct smb_filename *cwd_fname,
1186 const struct smb_filename *smb_fname)
1188 TALLOC_CTX *ctx = talloc_tos();
1189 const char *cwd_name = cwd_fname ? cwd_fname->base_name : NULL;
1190 const char *fname = smb_fname->base_name;
1191 struct smb_filename *resolved_fname;
1192 char *resolved_name = NULL;
1193 char *new_fname = NULL;
1194 bool allow_symlinks = true;
1195 bool allow_widelinks = false;
1197 DBG_DEBUG("check_reduced_name [%s] [%s]\n", fname, conn->connectpath);
1199 resolved_fname = SMB_VFS_REALPATH(conn, ctx, smb_fname);
1201 if (resolved_fname == NULL) {
1204 DEBUG(3,("check_reduced_name: Component not a "
1205 "directory in getting realpath for "
1207 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1210 char *dir_name = NULL;
1211 struct smb_filename dir_fname = {0};
1212 const char *last_component = NULL;
1214 /* Last component didn't exist.
1215 Remove it and try and canonicalise
1216 the directory name. */
1217 if (!parent_dirname(ctx, fname,
1220 return NT_STATUS_NO_MEMORY;
1223 dir_fname = (struct smb_filename)
1224 { .base_name = dir_name };
1225 resolved_fname = SMB_VFS_REALPATH(conn,
1228 if (resolved_fname == NULL) {
1229 NTSTATUS status = map_nt_error_from_unix(errno);
1231 if (errno == ENOENT || errno == ENOTDIR) {
1232 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1235 DEBUG(3,("check_reduce_name: "
1236 "couldn't get realpath for "
1239 nt_errstr(status)));
1242 resolved_name = talloc_asprintf(ctx,
1244 resolved_fname->base_name,
1246 if (resolved_name == NULL) {
1247 return NT_STATUS_NO_MEMORY;
1252 DEBUG(3,("check_reduced_name: couldn't get "
1253 "realpath for %s\n", fname));
1254 return map_nt_error_from_unix(errno);
1257 resolved_name = resolved_fname->base_name;
1260 DEBUG(10,("check_reduced_name realpath [%s] -> [%s]\n", fname,
1263 if (*resolved_name != '/') {
1264 DEBUG(0,("check_reduced_name: realpath doesn't return "
1265 "absolute paths !\n"));
1266 TALLOC_FREE(resolved_fname);
1267 return NT_STATUS_OBJECT_NAME_INVALID;
1270 allow_widelinks = lp_widelinks(SNUM(conn));
1271 allow_symlinks = lp_follow_symlinks(SNUM(conn));
1273 /* Common widelinks and symlinks checks. */
1274 if (!allow_widelinks || !allow_symlinks) {
1275 const char *conn_rootdir;
1278 conn_rootdir = SMB_VFS_CONNECTPATH(conn, smb_fname);
1279 if (conn_rootdir == NULL) {
1280 DEBUG(2, ("check_reduced_name: Could not get "
1282 TALLOC_FREE(resolved_fname);
1283 return NT_STATUS_ACCESS_DENIED;
1286 rootdir_len = strlen(conn_rootdir);
1289 * In the case of rootdir_len == 1, we know that
1290 * conn_rootdir is "/", and we also know that
1291 * resolved_name starts with a slash. So, in this
1292 * corner case, resolved_name is automatically a
1293 * sub-directory of the conn_rootdir. Thus we can skip
1294 * the string comparison and the next character checks
1295 * (which are even wrong in this case).
1297 if (rootdir_len != 1) {
1300 matched = (strncmp(conn_rootdir, resolved_name,
1302 if (!matched || (resolved_name[rootdir_len] != '/' &&
1303 resolved_name[rootdir_len] != '\0')) {
1304 DEBUG(2, ("check_reduced_name: Bad access "
1305 "attempt: %s is a symlink outside the "
1306 "share path\n", fname));
1307 DEBUGADD(2, ("conn_rootdir =%s\n",
1309 DEBUGADD(2, ("resolved_name=%s\n",
1311 TALLOC_FREE(resolved_fname);
1312 return NT_STATUS_ACCESS_DENIED;
1316 /* Extra checks if all symlinks are disallowed. */
1317 if (!allow_symlinks) {
1318 /* fname can't have changed in resolved_path. */
1319 const char *p = &resolved_name[rootdir_len];
1322 * UNIX filesystem semantics, names consisting
1323 * only of "." or ".." CANNOT be symlinks.
1325 if (ISDOT(fname) || ISDOTDOT(fname)) {
1330 DEBUG(2, ("check_reduced_name: logic error (%c) "
1331 "in resolved_name: %s\n",
1334 TALLOC_FREE(resolved_fname);
1335 return NT_STATUS_ACCESS_DENIED;
1341 * If cwd_name is present and not ".",
1342 * then fname is relative to that, not
1343 * the root of the share. Make sure the
1344 * path we check is the one the client
1345 * sent (cwd_name+fname).
1347 if (cwd_name != NULL && !ISDOT(cwd_name)) {
1348 new_fname = talloc_asprintf(ctx,
1352 if (new_fname == NULL) {
1353 TALLOC_FREE(resolved_fname);
1354 return NT_STATUS_NO_MEMORY;
1359 if (strcmp(fname, p)!=0) {
1360 DEBUG(2, ("check_reduced_name: Bad access "
1361 "attempt: %s is a symlink to %s\n",
1363 TALLOC_FREE(resolved_fname);
1364 TALLOC_FREE(new_fname);
1365 return NT_STATUS_ACCESS_DENIED;
1372 DBG_INFO("%s reduced to %s\n", fname, resolved_name);
1373 TALLOC_FREE(resolved_fname);
1374 TALLOC_FREE(new_fname);
1375 return NT_STATUS_OK;
1379 * XXX: This is temporary and there should be no callers of this once
1380 * smb_filename is plumbed through all path based operations.
1382 * Called when we know stream name parsing has already been done.
1384 int vfs_stat_smb_basename(struct connection_struct *conn,
1385 const struct smb_filename *smb_fname_in,
1386 SMB_STRUCT_STAT *psbuf)
1388 struct smb_filename smb_fname = {
1389 .base_name = discard_const_p(char, smb_fname_in->base_name),
1390 .flags = smb_fname_in->flags
1394 if (smb_fname.flags & SMB_FILENAME_POSIX_PATH) {
1395 ret = SMB_VFS_LSTAT(conn, &smb_fname);
1397 ret = SMB_VFS_STAT(conn, &smb_fname);
1401 *psbuf = smb_fname.st;
1407 * Ensure LSTAT is called for POSIX paths.
1410 NTSTATUS vfs_stat_fsp(files_struct *fsp)
1414 if(fsp->fh->fd == -1) {
1415 if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) {
1416 ret = SMB_VFS_LSTAT(fsp->conn, fsp->fsp_name);
1418 ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name);
1421 return map_nt_error_from_unix(errno);
1424 if(SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st) != 0) {
1425 return map_nt_error_from_unix(errno);
1428 return NT_STATUS_OK;
1432 * Initialize num_streams and streams, then call VFS op streaminfo
1434 NTSTATUS vfs_streaminfo(connection_struct *conn,
1435 struct files_struct *fsp,
1436 const struct smb_filename *smb_fname,
1437 TALLOC_CTX *mem_ctx,
1438 unsigned int *num_streams,
1439 struct stream_struct **streams)
1443 return SMB_VFS_STREAMINFO(conn,
1452 generate a file_id from a stat structure
1454 struct file_id vfs_file_id_from_sbuf(connection_struct *conn, const SMB_STRUCT_STAT *sbuf)
1456 return SMB_VFS_FILE_ID_CREATE(conn, sbuf);
1460 * Design of the smb_vfs_ev_glue infrastructure:
1462 * smb_vfs_ev_glue makes it possible to pass
1463 * down an tevent_context and pthreadpool_tevent
1464 * used for impersonation through the SMB_VFS stack.
1466 * tevent_req based function take an tevent_context as
1467 * there 2nd argument, e.g.:
1469 * struct tevent_req *something_send(TALLOC_CTX *mem_ctx,
1470 * struct tevent_context *ev,
1473 * For the SMB_VFS stack we'll use the following:
1475 * struct tevent_req *SMB_VFS_SOMETHING_SEND(TALLOC_CTX *mem_ctx,
1476 * const struct smb_vfs_ev_glue *evg,
1479 * Typically the 'evg' is just passed through the stack down
1480 * to vfs_default.c. In order to do real work an
1481 * tevent_context and pthreadpool_tevent are required
1482 * to do call a 'somthing()' syscall in an async fashion.
1483 * Therefore it will the following to get the pointer
1486 * ev = smb_vfs_ev_glue_ev_ctx(evg);
1487 * tp = smb_vfs_ev_glue_tp_chdir_safe(evg);
1489 * If some function in the stack is sure it needs to run as root
1490 * to get some information (after careful checks!), it used
1491 * to frame that work into become_root()/unbecome_root().
1492 * This can't work when using async functions!
1493 * Now it's possible to use something like this (simplified!):
1495 * ev = smb_vfs_ev_glue_ev_ctx(evg);
1496 * root_evg = smb_vfs_ev_glue_get_root_glue(evg);
1497 * subreq = SMB_VFS_SOMETHING_NEXT_SEND(state, root_evg, ...);
1498 * if (tevent_req_nomem(subreq, req)) {
1499 * return tevent_req_post(req, ev);
1501 * tevent_req_set_callback(subreq, module_something_done, req);
1505 * static void module_something_done(struct tevent_req *subreq)
1509 * status = SMB_VFS_SOMETHING_NEXT_RECV(subreq, &state->aio_state);
1510 * TALLOC_FREE(subreq);
1512 * tevent_req_done(req);
1515 * In the code above the something_send_fn() function of the next
1516 * module in the stack will be called as root.
1517 * The smb_vfs_call_something_*() glue code, which is the magic
1518 * behind the SMB_VFS_SOMETHING[_NEXT]_{SEND,RECV}() macros,
1519 * will look like this:
1521 * struct smb_vfs_call_something_state {
1522 * ssize_t (*recv_fn)(struct tevent_req *req,
1523 * struct vfs_aio_state *aio_state,
1526 * struct vfs_aio_state vfs_aio_state;
1530 * static void smb_vfs_call_something_done(struct tevent_req *subreq);
1532 * struct tevent_req *smb_vfs_call_something_send(
1533 * TALLOC_CTX *mem_ctx,
1534 * const struct smb_vfs_ev_glue *evg,
1535 * struct vfs_handle_struct *handle,
1538 * struct tevent_req *req = NULL;
1539 * struct smb_vfs_call_something_state *state = NULL;
1540 * struct tevent_req *subreq = NULL;
1543 * req = tevent_req_create(mem_ctx, &state,
1544 * struct smb_vfs_call_something_state);
1545 * if (req == NULL) {
1549 * VFS_FIND(something_send);
1550 * state->recv_fn = handle->fns->something_recv_fn;
1552 * ok = smb_vfs_ev_glue_push_use(evg, req);
1554 * tevent_req_error(req, EIO);
1555 * return tevent_req_post(req, evg->return_ev);
1558 * subreq = handle->fns->something_send_fn(mem_ctx,
1562 * smb_vfs_ev_glue_pop_use(evg);
1564 * if (tevent_req_nomem(subreq, req)) {
1565 * return tevent_req_post(req, evg->return_ev);
1567 * tevent_req_set_callback(subreq, smb_vfs_call_something_done, req);
1572 * static void smb_vfs_call_something_done(struct tevent_req *subreq)
1574 * struct tevent_req *req =
1575 * tevent_req_callback_data(subreq,
1576 * struct tevent_req);
1577 * struct smb_vfs_call_something_state *state =
1578 * tevent_req_data(req,
1579 * struct smb_vfs_call_something_state);
1581 * state->retval = state->recv_fn(subreq,
1582 * &state->vfs_aio_state,
1584 * TALLOC_FREE(subreq);
1586 * if (state->retval == -1) {
1587 * tevent_req_error(req, state->vfs_aio_state.error);
1590 * tevent_req_done(req);
1593 * ssize_t smb_vfs_call_something_recv(struct tevent_req *req,
1594 * struct vfs_aio_state *aio_state,
1597 * struct smb_vfs_call_something_state *state =
1598 * tevent_req_data(req,
1599 * struct smb_vfs_call_something_state);
1600 * ssize_t retval = state->retval;
1602 * if (tevent_req_is_unix_error(req, &aio_state->error)) {
1603 * tevent_req_received(req);
1607 * *aio_state = state->vfs_aio_state;
1610 * tevent_req_received(req);
1614 * The most important details are these:
1616 * 1. smb_vfs_ev_glue_push_use(evg, req):
1617 * - is a no-op if evg->run_ev and evg->return_ev are the same,
1618 * it means that we're already at the correct impersonation
1619 * and don't need any additional work to be done.
1620 * - Otherwise it will call tevent_req_defer_callback(req, evg->return_ev)
1621 * This means that tevent_req_error() and tevent_req_done()
1622 * will just trigger an immediate event on evg->return_ev.
1623 * Therefore the callers callback function will be called
1624 * in the impersonation of evg->return_ev! This is important
1625 * in order to get the impersonation correct on the way back
1626 * through the stack.
1627 * - It will call tevent_context_push_use(evg->run_ev),
1628 * which will start the impersonation to run_ev.
1629 * So the following code run in the correct context.
1630 * 2. handle->fns->something_send_fn(..., evg->next_glue, ...):
1631 * - We're passing evg->next_glue to the next module.
1632 * - Typically evg->next_glue points to evg again.
1633 * - In case evg->run_ev and evg->return_ev are not the same,
1634 * next_glue will have run_ev and return_ev pointing to evg->run_ev.
1635 * So that the switch from evg->run_ev to evg->return_ev
1636 * happens on the correct boundary.
1637 * 3. smb_vfs_ev_glue_pop_use(evg):
1638 * - is a no-op if evg->run_ev and evg->return_ev are the same,
1639 * it means that we're already at the correct impersonation
1640 * and don't need any additional work to be done.
1641 * - It will call tevent_context_pop_use(evg->run_ev),
1642 * which will revert the impersonation done in
1643 * smb_vfs_ev_glue_push_use().
1644 * 4. smb_vfs_call_something_send():
1645 * - The is called in the environment of evg->return_ev.
1646 * - So it needs to use tevent_req_post(req, evg->return_ev)
1647 * 5. smb_vfs_call_something_done():
1648 * - The is called in the environment of evg->run_ev
1649 * 6. smb_vfs_call_something_recv():
1650 * - The is called in the environment of evg->return_ev again.
1653 * Here are some more complex examples:
1655 * Example 1: only user_evg without switch to root
1657 * SMBD: already impersonated user_evg
1658 * evg'1 = smb2_req->user_evg
1659 * r'1 = SMB_VFS_*_SEND(evg'1); # smb_vfs_call_*_send()
1661 * | smb_vfs_ev_glue_push_use(evg'1, r'1);
1663 * | | # no-op run_ev == return_ev
1665 * | evg'2 = evg'1->next_glue;
1666 * | r'2 = module1_*_send(evg'2);
1669 * | | r'3 = SMB_VFS_*_NEXT_SEND(evg'3); # smb_vfs_call_*_send()
1671 * | | | smb_vfs_ev_glue_push_use(evg'3, r'3);
1673 * | | | | # no-op run_ev == return_ev
1675 * | | | evg'4 = evg'3->next_glue;
1676 * | | | r'4 = module2_*_send(evg'4);
1678 * | | | | evg'5 = evg'4
1679 * | | | | r'5 = SMB_VFS_*_NEXT_SEND(evg'5); # smb_vfs_call_*_send()
1681 * | | | | | smb_vfs_ev_glue_push_use(evg'5, r'5);
1683 * | | | | | | # no-op run_ev == return_ev
1685 * | | | | | evg'6 = evg'5->next_glue;
1686 * | | | | | r'6 = default_*_send(evg'6);
1688 * | | | | | | ev'6 = smb_vfs_ev_glue_ev_ctx(evg'6)
1689 * | | | | | | tp'6 = smb_vfs_ev_glue_tp_chdir_safe(evg'6)
1690 * | | | | | | r'7 = pthreadpool_tevent_send(ev'6, tp'6);
1692 * | | | | | | | pthread_create...
1694 * | | | | | | tevent_req_set_callback(r'7, default_*_done, r'6);
1696 * | | | | | smb_vfs_ev_glue_pop_use(evg'5);
1698 * | | | | | | # no-op run_ev == return_ev
1700 * | | | | | tevent_req_set_callback(r'6, smb_vfs_call_*_done, r'5);
1702 * | | | | tevent_req_set_callback(r'5, module2_*_done, r'4);
1704 * | | | smb_vfs_ev_glue_pop_use(evg'3);
1706 * | | | | # no-op run_ev == return_ev
1708 * | | | tevent_req_set_callback(r'4, smb_vfs_call_*_done, r'3);
1710 * | | tevent_req_set_callback(r'3, module1_*_done, r'2);
1712 * | smb_vfs_ev_glue_pop_use(evg'1);
1714 * | | # no-op run_ev == return_ev
1716 * | tevent_req_set_callback(r'2, smb_vfs_call_*_done, r'1);
1718 * tevent_req_set_callback(r'1, smbd_*_done, smb2_req);
1720 * Worker thread finished, just one event handler processes
1721 * everything as there's no impersonation change.
1723 * tevent_common_invoke_immediate_handler:
1725 * | before_immediate_handler(ev'6);
1727 * | | change_to_user()
1729 * | pthreadpool_tevent_job_done(r'7);
1731 * | | default_*_done(r'7);
1733 * | | | pthreadpool_tevent_recv(r'7);
1734 * | | | TALLOC_FREE(r'7);
1735 * | | | tevent_req_done('r6);
1737 * | | | | smb_vfs_call_*_done(r'6);
1739 * | | | | | default_*_recv(r'6);
1740 * | | | | | TALLOC_FREE(r'6)
1741 * | | | | | tevent_req_done(r'5);
1743 * | | | | | | module2_*_done(r'5):
1745 * | | | | | | | SMB_VFS_*_recv(r'5); # smb_vfs_call_*_recv()
1746 * | | | | | | | TALLOC_FREE(r'5)
1747 * | | | | | | | tevent_req_done(r'4);
1749 * | | | | | | | | smb_vfs_call_*_done(r'4);
1751 * | | | | | | | | | module2_*_recv(r'4);
1752 * | | | | | | | | | TALLOC_FREE(r'4)
1753 * | | | | | | | | | tevent_req_done(r'3);
1754 * | | | | | | | | | |
1755 * | | | | | | | | | | module1_*_done(r'3):
1756 * | | | | | | | | | | |
1757 * | | | | | | | | | | | SMB_VFS_*_recv(r'3); # smb_vfs_call_*_recv()
1758 * | | | | | | | | | | | TALLOC_FREE(r'3)
1759 * | | | | | | | | | | | tevent_req_done(r'2);
1760 * | | | | | | | | | | | |
1761 * | | | | | | | | | | | | smb_vfs_*_done(r'2);
1762 * | | | | | | | | | | | | |
1763 * | | | | | | | | | | | | | module1_*_recv(r'2);
1764 * | | | | | | | | | | | | | TALLOC_FREE(r'2)
1765 * | | | | | | | | | | | | | tevent_req_done(r'1);
1766 * | | | | | | | | | | | | | |
1767 * | | | | | | | | | | | | | | smbd_*_done(r'1);
1768 * | | | | | | | | | | | | | | |
1769 * | | | | | | | | | | | | | | | SMB_VFS_*_recv(r'1); # smb_vfs_call_*_recv()
1770 * | | | | | | | | | | | | | | | TALLOC_FREE(r'1)
1771 * | | | | | | | | | | | | | | | smbd_response_to_client()
1772 * | | | | | | | | | | | | | | | return
1773 * | | | | | | | | | | | | | | |
1774 * | | | | | | | | | | | | | | return
1775 * | | | | | | | | | | | | | |
1776 * | | | | | | | | | | | | | return
1777 * | | | | | | | | | | | | |
1778 * | | | | | | | | | | | | return
1779 * | | | | | | | | | | | |
1780 * | | | | | | | | | | | return
1781 * | | | | | | | | | | |
1782 * | | | | | | | | | | return
1783 * | | | | | | | | | |
1784 * | | | | | | | | | return
1786 * | | | | | | | | return
1788 * | | | | | | | return
1790 * | | | | | | return
1800 * | after_immediate_handler(ev'6);
1802 * | | # lazy no change_to_user()
1807 * Example 2: start with user_evg and let module1 switch to root
1809 * SMBD: already impersonated user_evg
1810 * evg'1 = smb2_req->user_evg
1811 * r'1 = SMB_VFS_*_SEND(evg'1); # smb_vfs_call_*_send()
1813 * | smb_vfs_ev_glue_push_use(evg'1, r'1);
1815 * | | # no-op run_ev == return_ev
1817 * | evg'2 = evg'1->next_glue;
1818 * | r'2 = module1_*_send(evg'2);
1820 * | | evg'3 = smb_vfs_ev_glue_get_root_glue(evg'2)
1821 * | | r'3 = SMB_VFS_*_NEXT_SEND(evg'3); # smb_vfs_call_*_send()
1823 * | | | smb_vfs_ev_glue_push_use(evg'3, r'3);
1825 * | | | | tevent_req_defer_callback(r'3, evg'3->return_ev);
1826 * | | | | tevent_context_push_use(evg'3->run_ev)
1828 * | | | | | become_root()
1831 * | | | evg'4 = evg'3->next_glue;
1832 * | | | r'4 = module2_*_send(evg'4);
1834 * | | | | evg'5 = smb_vfs_ev_glue_get_root_glue(evg'4)
1835 * | | | | r'5 = SMB_VFS_*_NEXT_SEND(evg'5); # smb_vfs_call_*_send()
1837 * | | | | | smb_vfs_ev_glue_push_use(evg'5, r'5);
1839 * | | | | | | # no-op run_ev == return_ev, already root
1841 * | | | | | evg'6 = evg'5->next_glue;
1842 * | | | | | r'6 = default_*_send(evg'6);
1844 * | | | | | | ev'6 = smb_vfs_ev_glue_ev_ctx(evg'6)
1845 * | | | | | | tp'6 = smb_vfs_ev_glue_tp_chdir_safe(evg'6)
1846 * | | | | | | r'7 = pthreadpool_tevent_send(ev'6, tp'6);
1848 * | | | | | | | pthread_create...
1850 * | | | | | | tevent_req_set_callback(r'7, default_*_done, r'6);
1852 * | | | | | smb_vfs_ev_glue_pop_use(evg'5);
1854 * | | | | | | # no-op run_ev == return_ev, still stay as root
1856 * | | | | | tevent_req_set_callback(r'6, smb_vfs_*_done, r'5);
1858 * | | | | tevent_req_set_callback(r'5, module2_*_done, r'4);
1860 * | | | smb_vfs_ev_glue_pop_use(evg'3);
1862 * | | | | tevent_context_pop_use(evg'3->run_ev)
1864 * | | | | | unbecome_root()
1866 * | | | tevent_req_set_callback(r'4, smb_vfs_*_done, r'3);
1868 * | | tevent_req_set_callback(r'3, module1_*_done, r'2);
1870 * | smb_vfs_ev_glue_pop_use(evg'1);
1872 * | | # no-op run_ev == return_ev
1874 * | tevent_req_set_callback(r'2, smb_vfs_*_done, r'1);
1876 * tevent_req_set_callback(r'1, smbd_*_done, smb2_req);
1878 * Worker thread finished, just one event handler processes
1879 * everything as there's no impersonation change.
1881 * tevent_common_invoke_immediate_handler:
1883 * | before_immediate_handler(ev'6);
1887 * | pthreadpool_tevent_job_done(r'7);
1889 * | | default_*_done(r'7);
1891 * | | | pthreadpool_tevent_recv(r'7);
1892 * | | | TALLOC_FREE(r'7);
1893 * | | | tevent_req_done('r6);
1895 * | | | | smb_vfs_*_done(r'6);
1897 * | | | | | default_*_recv(r'6);
1898 * | | | | | TALLOC_FREE(r'6)
1899 * | | | | | tevent_req_done(r'5);
1901 * | | | | | | module2_*_done(r'5):
1903 * | | | | | | | SMB_VFS_*_recv(r'5);
1904 * | | | | | | | TALLOC_FREE(r'5)
1905 * | | | | | | | tevent_req_done(r'4);
1907 * | | | | | | | | smb_vfs_*_done(r'4);
1909 * | | | | | | | | | module2_*_recv(r'4);
1910 * | | | | | | | | | TALLOC_FREE(r'4)
1911 * | | | | | | | | | tevent_req_done(r'3);
1912 * | | | | | | | | | | return
1913 * | | | | | | | | | |
1914 * | | | | | | | | | return
1916 * | | | | | | | | return
1918 * | | | | | | | return
1920 * | | | | | | return
1931 * | after_immediate_handler(ev'6);
1933 * | | unbecome_root()
1937 * tevent_common_invoke_immediate_handler:
1939 * | before_immediate_handler(ev'6);
1941 * | | change_to_user()
1943 * | tevent_req_trigger();
1945 * | _tevent_req_notify_callback(r'3)
1947 * | | module1_*_done(r'3):
1949 * | | | SMB_VFS_*_recv(r'3);
1950 * | | | TALLOC_FREE(r'3)
1951 * | | | tevent_req_done(r'2);
1953 * | | | | smb_vfs_*_done(r'2);
1955 * | | | | | module1_*_recv(r'2);
1956 * | | | | | TALLOC_FREE(r'2)
1957 * | | | | | tevent_req_done(r'1);
1959 * | | | | | | smbd_*_done(r'1);
1961 * | | | | | | | SMB_VFS_*_recv(r'1);
1962 * | | | | | | | TALLOC_FREE(r'1)
1963 * | | | | | | | smbd_response_to_client()
1964 * | | | | | | | return
1966 * | | | | | | return
1976 * | after_immediate_handler(ev'6);
1978 * | | # lazy no change_to_user()
1983 struct smb_vfs_ev_glue {
1985 * The event context that should be used
1986 * to report the result back.
1988 * The is basically the callers context.
1990 struct tevent_context *return_ev;
1993 * The event context and threadpool wrappers
1994 * the current context should use.
1996 * tp_fd_safe only allows fd based functions
1997 * which don't require impersonation, this
1998 * is basically the raw threadpool.
2000 * tp_path_safe allows path based functions
2001 * to be called under the correct impersonation.
2002 * But chdir/fchdir is not allowed!
2003 * Typically calls like openat() or other *at()
2006 * tp_chdir_safe is like path_safe, but also
2007 * allows chdir/fchdir to be called, the job
2008 * can safely return with a changed directory,
2009 * the threadpool wrapper takes care of
2010 * a cleanup if required.
2011 * This is needed if *at() syscalls need
2012 * to be simulated by fchdir();$syscall(),
2015 * The distinction between these threadpool
2016 * is required because of OS limitations
2018 * - only Linux supports per thread
2019 * credentials (seteuid....)
2020 * - only Linux supports a per thread
2021 * current working directory,
2022 * using unshare(CLONE_FS). But
2023 * in some constrained container
2024 * environments even that is not available
2027 * tp_fd_safe is typically the raw threadpool
2028 * without a wrapper.
2030 * On Linux tp_path_safe and tp_chdir_safe
2031 * are typically the same (if unshare(CLONE_FS) is available)
2032 * they're implemented as wrappers of the raw threadpool.
2034 * On other OSes tp_path_safe is a wrapper
2035 * arround a sync threadpool (without real threads, just blocking
2036 * the main thread), but hidden behind the pthreadpool_tevent
2037 * api in order to make the restriction transparent.
2039 * On other OSes tp_chdir_safe is a wrapper
2040 * arround a sync threadpool (without real threads, just blocking
2041 * the main thread), but hidden behind the pthreadpool_tevent
2042 * api in order to make the restriction transparent.
2043 * It just remembers/restores the current working directory,
2044 * typically using open(".", O_RDONLY | O_DIRECTORY) and fchdir().
2046 struct tevent_context *run_ev;
2047 struct pthreadpool_tevent *run_tp_fd_safe;
2048 struct pthreadpool_tevent *run_tp_path_safe;
2049 struct pthreadpool_tevent *run_tp_chdir_safe;
2052 * The glue that should be passed down
2053 * to sub request in the stack.
2055 * Typically this points to itself.
2057 * But smb_vfs_ev_glue_create_switch() allows
2058 * to create context that can switch
2059 * between two user glues.
2061 const struct smb_vfs_ev_glue *next_glue;
2064 * If some code path wants to run
2065 * some constraint code as root,
2066 * basically an async version of become_root()
2067 * and unbecome_root().
2069 * The caller can call smb_vfs_ev_glue_get_root_glue()
2070 * to get a root glue that can be passed
2071 * to the SMB_VFS_*_SEND() function that
2072 * should run as root.
2074 * Note that the callback (registered with
2075 * tevent_req_set_callback()) won't run as
2078 const struct smb_vfs_ev_glue *root_glue;
2081 static struct smb_vfs_ev_glue *smb_vfs_ev_glue_create_internal(
2082 TALLOC_CTX *mem_ctx,
2083 struct tevent_context *return_ev,
2084 struct tevent_context *run_ev,
2085 struct pthreadpool_tevent *run_tp_fd_safe,
2086 struct pthreadpool_tevent *run_tp_path_safe,
2087 struct pthreadpool_tevent *run_tp_chdir_safe)
2089 struct smb_vfs_ev_glue *evg = NULL;
2091 evg = talloc_zero(mem_ctx, struct smb_vfs_ev_glue);
2095 *evg = (struct smb_vfs_ev_glue) {
2096 .return_ev = return_ev,
2098 .run_tp_fd_safe = run_tp_fd_safe,
2099 .run_tp_path_safe = run_tp_path_safe,
2100 .run_tp_chdir_safe = run_tp_chdir_safe,
2107 struct tevent_context *smb_vfs_ev_glue_ev_ctx(const struct smb_vfs_ev_glue *evg)
2112 struct pthreadpool_tevent *smb_vfs_ev_glue_tp_fd_safe(const struct smb_vfs_ev_glue *evg)
2114 return evg->run_tp_fd_safe;
2117 struct pthreadpool_tevent *smb_vfs_ev_glue_tp_path_safe(const struct smb_vfs_ev_glue *evg)
2119 return evg->run_tp_path_safe;
2122 struct pthreadpool_tevent *smb_vfs_ev_glue_tp_chdir_safe(const struct smb_vfs_ev_glue *evg)
2124 return evg->run_tp_chdir_safe;
2127 const struct smb_vfs_ev_glue *smb_vfs_ev_glue_get_root_glue(const struct smb_vfs_ev_glue *evg)
2129 return evg->root_glue;
2132 struct smb_vfs_ev_glue *smb_vfs_ev_glue_create(TALLOC_CTX *mem_ctx,
2133 struct tevent_context *user_ev,
2134 struct pthreadpool_tevent *user_tp_fd_safe,
2135 struct pthreadpool_tevent *user_tp_path_safe,
2136 struct pthreadpool_tevent *user_tp_chdir_safe,
2137 struct tevent_context *root_ev,
2138 struct pthreadpool_tevent *root_tp_fd_safe,
2139 struct pthreadpool_tevent *root_tp_path_safe,
2140 struct pthreadpool_tevent *root_tp_chdir_safe)
2142 struct smb_vfs_ev_glue *evg_uu = NULL;
2143 struct smb_vfs_ev_glue *evg_ru = NULL;
2144 struct smb_vfs_ev_glue *evg_rr = NULL;
2147 * The top level glue (directly returned from this function).
2149 * It uses user_ev and user_tp_* only.
2151 evg_uu = smb_vfs_ev_glue_create_internal(mem_ctx,
2152 user_ev, /* return_ev */
2153 user_ev, /* run_ev */
2156 user_tp_chdir_safe);
2157 if (evg_uu == NULL) {
2162 * The first root glue (returned by smb_vfs_ev_glue_get_root_glue()).
2164 * It uses root_ev and root_tp, but user_ev as return ev,
2165 * which means that the caller's callback (registered with
2166 * tevent_req_set_callback()) will run as user_ev.
2168 evg_ru = smb_vfs_ev_glue_create_internal(evg_uu,
2169 user_ev, /* return_ev */
2170 root_ev, /* run_ev */
2173 root_tp_chdir_safe);
2174 if (evg_ru == NULL) {
2175 TALLOC_FREE(evg_uu);
2180 * The second root glue (returned by smb_vfs_ev_glue_get_root_glue() on
2181 * root glue itself. This means code can always call
2182 * smb_vfs_ev_glue_get_root_glue() and don't have to care if the
2183 * passed glue is already a root glue.
2185 * This will then recursively point to its own root_glue pointer.
2187 * It only uses root_ev and root_tp.
2189 evg_rr = smb_vfs_ev_glue_create_internal(evg_ru,
2190 root_ev, /* return_ev */
2191 root_ev, /* run_ev */
2194 root_tp_chdir_safe);
2195 if (evg_rr == NULL) {
2196 TALLOC_FREE(evg_uu);
2201 * We now setup the glue hierachie.
2203 * Search for "Design of the smb_vfs_ev_glue infrastructure" above
2204 * for a detailed description how the chain works.
2206 * "Example 2: start with user_evg and let module1 switch to root"
2207 * explains it for the root_glue chaining.
2209 evg_rr->root_glue = evg_rr;
2210 evg_ru->root_glue = evg_rr;
2211 evg_uu->root_glue = evg_ru;
2214 * As evg_ru is a boundary with
2215 * run_ev != return_ev, we need to
2216 * alter its next_glue.
2218 evg_ru->next_glue = evg_rr;
2224 * This can be used to create a temporary glue
2225 * if you need to switch between two user contexts
2227 * It's the caller's duty to make sure both
2228 * glues stay alive for the lifetime of the
2231 struct smb_vfs_ev_glue *smb_vfs_ev_glue_create_switch(
2232 TALLOC_CTX *mem_ctx,
2233 const struct smb_vfs_ev_glue *return_evg,
2234 const struct smb_vfs_ev_glue *run_evg)
2236 const struct smb_vfs_ev_glue *run_root = run_evg->root_glue;
2237 struct smb_vfs_ev_glue *evg_u = NULL;
2238 struct smb_vfs_ev_glue *evg_r = NULL;
2241 * Here we basically need to dup run_evg (and run_evg->root_glue)
2242 * and replace their return_ev with return_evg->return_ev.
2244 * We need to put the new evgs in front of the chain...
2246 evg_u = smb_vfs_ev_glue_create_internal(mem_ctx,
2247 return_evg->return_ev,
2249 run_evg->run_tp_fd_safe,
2250 run_evg->run_tp_path_safe,
2251 run_evg->run_tp_chdir_safe);
2252 if (evg_u == NULL) {
2256 evg_r = smb_vfs_ev_glue_create_internal(evg_u,
2257 return_evg->return_ev,
2259 run_root->run_tp_fd_safe,
2260 run_root->run_tp_path_safe,
2261 run_root->run_tp_chdir_safe);
2262 if (evg_r == NULL) {
2267 * evg_r is a boundary with run_ev != return_ev.
2268 * As run_root is also a boundary, we need to
2269 * use run_root->next_glue in order to get
2270 * a glue that stays as root.
2272 * The same applies to the chaining of root
2275 evg_r->next_glue = run_root->next_glue;
2276 evg_r->root_glue = run_root->root_glue;
2279 * evg_r is a boundary with run_ev != return_ev.
2280 * But run_evg is typically not a boundary,
2281 * we use it directly as next_glue.
2283 * And the root_glue is the one we constructed above.
2285 evg_u->next_glue = run_evg;
2286 evg_u->root_glue = evg_r;
2291 static bool smb_vfs_ev_glue_push_use(const struct smb_vfs_ev_glue *evg,
2292 struct tevent_req *req)
2294 if (evg->run_ev == evg->return_ev) {
2296 * We're already in the correct
2297 * impersonation environment.
2303 * Make sure that our callers callback function
2304 * will be called in the return_ev environment.
2306 tevent_req_defer_callback(req, evg->return_ev);
2309 * let the event context wrapper do
2310 * the required impersonation.
2312 return tevent_context_push_use(evg->run_ev);
2315 static void smb_vfs_ev_glue_pop_use(const struct smb_vfs_ev_glue *evg)
2317 if (evg->run_ev == evg->return_ev) {
2319 * smb_vfs_ev_glue_push_use() didn't
2320 * change the impersonation environment.
2326 * undo the impersonation
2328 tevent_context_pop_use(evg->run_ev);
2331 int smb_vfs_call_connect(struct vfs_handle_struct *handle,
2332 const char *service, const char *user)
2335 return handle->fns->connect_fn(handle, service, user);
2338 void smb_vfs_call_disconnect(struct vfs_handle_struct *handle)
2340 VFS_FIND(disconnect);
2341 handle->fns->disconnect_fn(handle);
2344 uint64_t smb_vfs_call_disk_free(struct vfs_handle_struct *handle,
2345 const struct smb_filename *smb_fname,
2350 VFS_FIND(disk_free);
2351 return handle->fns->disk_free_fn(handle, smb_fname,
2352 bsize, dfree, dsize);
2355 int smb_vfs_call_get_quota(struct vfs_handle_struct *handle,
2356 const struct smb_filename *smb_fname,
2357 enum SMB_QUOTA_TYPE qtype,
2361 VFS_FIND(get_quota);
2362 return handle->fns->get_quota_fn(handle, smb_fname, qtype, id, qt);
2365 int smb_vfs_call_set_quota(struct vfs_handle_struct *handle,
2366 enum SMB_QUOTA_TYPE qtype, unid_t id,
2369 VFS_FIND(set_quota);
2370 return handle->fns->set_quota_fn(handle, qtype, id, qt);
2373 int smb_vfs_call_get_shadow_copy_data(struct vfs_handle_struct *handle,
2374 struct files_struct *fsp,
2375 struct shadow_copy_data *shadow_copy_data,
2378 VFS_FIND(get_shadow_copy_data);
2379 return handle->fns->get_shadow_copy_data_fn(handle, fsp,
2383 int smb_vfs_call_statvfs(struct vfs_handle_struct *handle,
2384 const struct smb_filename *smb_fname,
2385 struct vfs_statvfs_struct *statbuf)
2388 return handle->fns->statvfs_fn(handle, smb_fname, statbuf);
2391 uint32_t smb_vfs_call_fs_capabilities(struct vfs_handle_struct *handle,
2392 enum timestamp_set_resolution *p_ts_res)
2394 VFS_FIND(fs_capabilities);
2395 return handle->fns->fs_capabilities_fn(handle, p_ts_res);
2398 NTSTATUS smb_vfs_call_get_dfs_referrals(struct vfs_handle_struct *handle,
2399 struct dfs_GetDFSReferral *r)
2401 VFS_FIND(get_dfs_referrals);
2402 return handle->fns->get_dfs_referrals_fn(handle, r);
2405 DIR *smb_vfs_call_opendir(struct vfs_handle_struct *handle,
2406 const struct smb_filename *smb_fname,
2408 uint32_t attributes)
2411 return handle->fns->opendir_fn(handle, smb_fname, mask, attributes);
2414 DIR *smb_vfs_call_fdopendir(struct vfs_handle_struct *handle,
2415 struct files_struct *fsp,
2417 uint32_t attributes)
2419 VFS_FIND(fdopendir);
2420 return handle->fns->fdopendir_fn(handle, fsp, mask, attributes);
2423 struct dirent *smb_vfs_call_readdir(struct vfs_handle_struct *handle,
2425 SMB_STRUCT_STAT *sbuf)
2428 return handle->fns->readdir_fn(handle, dirp, sbuf);
2431 void smb_vfs_call_seekdir(struct vfs_handle_struct *handle,
2432 DIR *dirp, long offset)
2435 handle->fns->seekdir_fn(handle, dirp, offset);
2438 long smb_vfs_call_telldir(struct vfs_handle_struct *handle,
2442 return handle->fns->telldir_fn(handle, dirp);
2445 void smb_vfs_call_rewind_dir(struct vfs_handle_struct *handle,
2448 VFS_FIND(rewind_dir);
2449 handle->fns->rewind_dir_fn(handle, dirp);
2452 int smb_vfs_call_mkdir(struct vfs_handle_struct *handle,
2453 const struct smb_filename *smb_fname,
2457 return handle->fns->mkdir_fn(handle, smb_fname, mode);
2460 int smb_vfs_call_rmdir(struct vfs_handle_struct *handle,
2461 const struct smb_filename *smb_fname)
2464 return handle->fns->rmdir_fn(handle, smb_fname);
2467 int smb_vfs_call_closedir(struct vfs_handle_struct *handle,
2471 return handle->fns->closedir_fn(handle, dir);
2474 int smb_vfs_call_open(struct vfs_handle_struct *handle,
2475 struct smb_filename *smb_fname, struct files_struct *fsp,
2476 int flags, mode_t mode)
2479 return handle->fns->open_fn(handle, smb_fname, fsp, flags, mode);
2482 NTSTATUS smb_vfs_call_create_file(struct vfs_handle_struct *handle,
2483 struct smb_request *req,
2484 uint16_t root_dir_fid,
2485 struct smb_filename *smb_fname,
2486 uint32_t access_mask,
2487 uint32_t share_access,
2488 uint32_t create_disposition,
2489 uint32_t create_options,
2490 uint32_t file_attributes,
2491 uint32_t oplock_request,
2492 struct smb2_lease *lease,
2493 uint64_t allocation_size,
2494 uint32_t private_flags,
2495 struct security_descriptor *sd,
2496 struct ea_list *ea_list,
2497 files_struct **result,
2499 const struct smb2_create_blobs *in_context_blobs,
2500 struct smb2_create_blobs *out_context_blobs)
2502 VFS_FIND(create_file);
2503 return handle->fns->create_file_fn(
2504 handle, req, root_dir_fid, smb_fname, access_mask,
2505 share_access, create_disposition, create_options,
2506 file_attributes, oplock_request, lease, allocation_size,
2507 private_flags, sd, ea_list,
2508 result, pinfo, in_context_blobs, out_context_blobs);
2511 int smb_vfs_call_close(struct vfs_handle_struct *handle,
2512 struct files_struct *fsp)
2515 return handle->fns->close_fn(handle, fsp);
2518 ssize_t smb_vfs_call_pread(struct vfs_handle_struct *handle,
2519 struct files_struct *fsp, void *data, size_t n,
2523 return handle->fns->pread_fn(handle, fsp, data, n, offset);
2526 struct smb_vfs_call_pread_state {
2527 ssize_t (*recv_fn)(struct tevent_req *req, struct vfs_aio_state *vfs_aio_state);
2529 struct vfs_aio_state vfs_aio_state;
2532 static void smb_vfs_call_pread_done(struct tevent_req *subreq);
2534 struct tevent_req *smb_vfs_call_pread_send(struct vfs_handle_struct *handle,
2535 TALLOC_CTX *mem_ctx,
2536 struct tevent_context *ev,
2537 struct files_struct *fsp,
2539 size_t n, off_t offset)
2541 struct tevent_req *req, *subreq;
2542 struct smb_vfs_call_pread_state *state;
2544 req = tevent_req_create(mem_ctx, &state,
2545 struct smb_vfs_call_pread_state);
2549 VFS_FIND(pread_send);
2550 state->recv_fn = handle->fns->pread_recv_fn;
2552 subreq = handle->fns->pread_send_fn(handle, state, ev, fsp, data, n,
2554 if (tevent_req_nomem(subreq, req)) {
2555 return tevent_req_post(req, ev);
2557 tevent_req_set_callback(subreq, smb_vfs_call_pread_done, req);
2561 static void smb_vfs_call_pread_done(struct tevent_req *subreq)
2563 struct tevent_req *req = tevent_req_callback_data(
2564 subreq, struct tevent_req);
2565 struct smb_vfs_call_pread_state *state = tevent_req_data(
2566 req, struct smb_vfs_call_pread_state);
2568 state->retval = state->recv_fn(subreq, &state->vfs_aio_state);
2569 TALLOC_FREE(subreq);
2570 if (state->retval == -1) {
2571 tevent_req_error(req, state->vfs_aio_state.error);
2574 tevent_req_done(req);
2577 ssize_t SMB_VFS_PREAD_RECV(struct tevent_req *req,
2578 struct vfs_aio_state *vfs_aio_state)
2580 struct smb_vfs_call_pread_state *state = tevent_req_data(
2581 req, struct smb_vfs_call_pread_state);
2584 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
2585 tevent_req_received(req);
2588 *vfs_aio_state = state->vfs_aio_state;
2589 retval = state->retval;
2590 tevent_req_received(req);
2594 ssize_t smb_vfs_call_pwrite(struct vfs_handle_struct *handle,
2595 struct files_struct *fsp, const void *data,
2596 size_t n, off_t offset)
2599 return handle->fns->pwrite_fn(handle, fsp, data, n, offset);
2602 struct smb_vfs_call_pwrite_state {
2603 ssize_t (*recv_fn)(struct tevent_req *req, struct vfs_aio_state *vfs_aio_state);
2605 struct vfs_aio_state vfs_aio_state;
2608 static void smb_vfs_call_pwrite_done(struct tevent_req *subreq);
2610 struct tevent_req *smb_vfs_call_pwrite_send(struct vfs_handle_struct *handle,
2611 TALLOC_CTX *mem_ctx,
2612 struct tevent_context *ev,
2613 struct files_struct *fsp,
2615 size_t n, off_t offset)
2617 struct tevent_req *req, *subreq;
2618 struct smb_vfs_call_pwrite_state *state;
2620 req = tevent_req_create(mem_ctx, &state,
2621 struct smb_vfs_call_pwrite_state);
2625 VFS_FIND(pwrite_send);
2626 state->recv_fn = handle->fns->pwrite_recv_fn;
2628 subreq = handle->fns->pwrite_send_fn(handle, state, ev, fsp, data, n,
2630 if (tevent_req_nomem(subreq, req)) {
2631 return tevent_req_post(req, ev);
2633 tevent_req_set_callback(subreq, smb_vfs_call_pwrite_done, req);
2637 static void smb_vfs_call_pwrite_done(struct tevent_req *subreq)
2639 struct tevent_req *req = tevent_req_callback_data(
2640 subreq, struct tevent_req);
2641 struct smb_vfs_call_pwrite_state *state = tevent_req_data(
2642 req, struct smb_vfs_call_pwrite_state);
2644 state->retval = state->recv_fn(subreq, &state->vfs_aio_state);
2645 TALLOC_FREE(subreq);
2646 if (state->retval == -1) {
2647 tevent_req_error(req, state->vfs_aio_state.error);
2650 tevent_req_done(req);
2653 ssize_t SMB_VFS_PWRITE_RECV(struct tevent_req *req,
2654 struct vfs_aio_state *vfs_aio_state)
2656 struct smb_vfs_call_pwrite_state *state = tevent_req_data(
2657 req, struct smb_vfs_call_pwrite_state);
2660 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
2661 tevent_req_received(req);
2664 *vfs_aio_state = state->vfs_aio_state;
2665 retval = state->retval;
2666 tevent_req_received(req);
2670 off_t smb_vfs_call_lseek(struct vfs_handle_struct *handle,
2671 struct files_struct *fsp, off_t offset,
2675 return handle->fns->lseek_fn(handle, fsp, offset, whence);
2678 ssize_t smb_vfs_call_sendfile(struct vfs_handle_struct *handle, int tofd,
2679 files_struct *fromfsp, const DATA_BLOB *header,
2680 off_t offset, size_t count)
2683 return handle->fns->sendfile_fn(handle, tofd, fromfsp, header, offset,
2687 ssize_t smb_vfs_call_recvfile(struct vfs_handle_struct *handle, int fromfd,
2688 files_struct *tofsp, off_t offset,
2692 return handle->fns->recvfile_fn(handle, fromfd, tofsp, offset, count);
2695 int smb_vfs_call_rename(struct vfs_handle_struct *handle,
2696 const struct smb_filename *smb_fname_src,
2697 const struct smb_filename *smb_fname_dst)
2700 return handle->fns->rename_fn(handle, smb_fname_src, smb_fname_dst);
2703 struct smb_vfs_call_fsync_state {
2704 int (*recv_fn)(struct tevent_req *req, struct vfs_aio_state *vfs_aio_state);
2706 struct vfs_aio_state vfs_aio_state;
2709 static void smb_vfs_call_fsync_done(struct tevent_req *subreq);
2711 struct tevent_req *smb_vfs_call_fsync_send(struct vfs_handle_struct *handle,
2712 TALLOC_CTX *mem_ctx,
2713 struct tevent_context *ev,
2714 struct files_struct *fsp)
2716 struct tevent_req *req, *subreq;
2717 struct smb_vfs_call_fsync_state *state;
2719 req = tevent_req_create(mem_ctx, &state,
2720 struct smb_vfs_call_fsync_state);
2724 VFS_FIND(fsync_send);
2725 state->recv_fn = handle->fns->fsync_recv_fn;
2727 subreq = handle->fns->fsync_send_fn(handle, state, ev, fsp);
2728 if (tevent_req_nomem(subreq, req)) {
2729 return tevent_req_post(req, ev);
2731 tevent_req_set_callback(subreq, smb_vfs_call_fsync_done, req);
2735 static void smb_vfs_call_fsync_done(struct tevent_req *subreq)
2737 struct tevent_req *req = tevent_req_callback_data(
2738 subreq, struct tevent_req);
2739 struct smb_vfs_call_fsync_state *state = tevent_req_data(
2740 req, struct smb_vfs_call_fsync_state);
2742 state->retval = state->recv_fn(subreq, &state->vfs_aio_state);
2743 TALLOC_FREE(subreq);
2744 if (state->retval == -1) {
2745 tevent_req_error(req, state->vfs_aio_state.error);
2748 tevent_req_done(req);
2751 int SMB_VFS_FSYNC_RECV(struct tevent_req *req, struct vfs_aio_state *vfs_aio_state)
2753 struct smb_vfs_call_fsync_state *state = tevent_req_data(
2754 req, struct smb_vfs_call_fsync_state);
2757 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
2758 tevent_req_received(req);
2761 *vfs_aio_state = state->vfs_aio_state;
2762 retval = state->retval;
2763 tevent_req_received(req);
2768 * Synchronous version of fsync, built from backend
2769 * async VFS primitives. Uses a temporary sub-event
2770 * context (NOT NESTED).
2773 int smb_vfs_fsync_sync(files_struct *fsp)
2775 TALLOC_CTX *frame = talloc_stackframe();
2776 struct tevent_req *req = NULL;
2777 struct vfs_aio_state aio_state = { 0 };
2780 struct tevent_context *ev = samba_tevent_context_init(frame);
2786 req = SMB_VFS_FSYNC_SEND(talloc_tos(), ev, fsp);
2791 ok = tevent_req_poll(req, ev);
2796 ret = SMB_VFS_FSYNC_RECV(req, &aio_state);
2801 if (aio_state.error != 0) {
2802 errno = aio_state.error;
2807 int smb_vfs_call_stat(struct vfs_handle_struct *handle,
2808 struct smb_filename *smb_fname)
2811 return handle->fns->stat_fn(handle, smb_fname);
2814 int smb_vfs_call_fstat(struct vfs_handle_struct *handle,
2815 struct files_struct *fsp, SMB_STRUCT_STAT *sbuf)
2818 return handle->fns->fstat_fn(handle, fsp, sbuf);
2821 int smb_vfs_call_lstat(struct vfs_handle_struct *handle,
2822 struct smb_filename *smb_filename)
2825 return handle->fns->lstat_fn(handle, smb_filename);
2828 uint64_t smb_vfs_call_get_alloc_size(struct vfs_handle_struct *handle,
2829 struct files_struct *fsp,
2830 const SMB_STRUCT_STAT *sbuf)
2832 VFS_FIND(get_alloc_size);
2833 return handle->fns->get_alloc_size_fn(handle, fsp, sbuf);
2836 int smb_vfs_call_unlink(struct vfs_handle_struct *handle,
2837 const struct smb_filename *smb_fname)
2840 return handle->fns->unlink_fn(handle, smb_fname);
2843 int smb_vfs_call_chmod(struct vfs_handle_struct *handle,
2844 const struct smb_filename *smb_fname,
2848 return handle->fns->chmod_fn(handle, smb_fname, mode);
2851 int smb_vfs_call_fchmod(struct vfs_handle_struct *handle,
2852 struct files_struct *fsp, mode_t mode)
2855 return handle->fns->fchmod_fn(handle, fsp, mode);
2858 int smb_vfs_call_chown(struct vfs_handle_struct *handle,
2859 const struct smb_filename *smb_fname,
2864 return handle->fns->chown_fn(handle, smb_fname, uid, gid);
2867 int smb_vfs_call_fchown(struct vfs_handle_struct *handle,
2868 struct files_struct *fsp, uid_t uid, gid_t gid)
2871 return handle->fns->fchown_fn(handle, fsp, uid, gid);
2874 int smb_vfs_call_lchown(struct vfs_handle_struct *handle,
2875 const struct smb_filename *smb_fname,
2880 return handle->fns->lchown_fn(handle, smb_fname, uid, gid);
2883 NTSTATUS vfs_chown_fsp(files_struct *fsp, uid_t uid, gid_t gid)
2886 bool as_root = false;
2889 if (fsp->fh->fd != -1) {
2891 ret = SMB_VFS_FCHOWN(fsp, uid, gid);
2893 return NT_STATUS_OK;
2895 if (ret == -1 && errno != ENOSYS) {
2896 return map_nt_error_from_unix(errno);
2900 as_root = (geteuid() == 0);
2904 * We are being asked to chown as root. Make
2905 * sure we chdir() into the path to pin it,
2906 * and always act using lchown to ensure we
2907 * don't deref any symbolic links.
2909 char *parent_dir = NULL;
2910 const char *final_component = NULL;
2911 struct smb_filename *local_smb_fname = NULL;
2912 struct smb_filename parent_dir_fname = {0};
2913 struct smb_filename *saved_dir_fname = NULL;
2915 saved_dir_fname = vfs_GetWd(talloc_tos(),fsp->conn);
2916 if (!saved_dir_fname) {
2917 status = map_nt_error_from_unix(errno);
2918 DEBUG(0,("vfs_chown_fsp: failed to get "
2919 "current working directory. Error was %s\n",
2924 if (!parent_dirname(talloc_tos(),
2925 fsp->fsp_name->base_name,
2927 &final_component)) {
2928 return NT_STATUS_NO_MEMORY;
2931 parent_dir_fname = (struct smb_filename) {
2932 .base_name = parent_dir,
2933 .flags = fsp->fsp_name->flags
2936 /* cd into the parent dir to pin it. */
2937 ret = vfs_ChDir(fsp->conn, &parent_dir_fname);
2939 return map_nt_error_from_unix(errno);
2942 local_smb_fname = synthetic_smb_fname(talloc_tos(),
2946 fsp->fsp_name->flags);
2947 if (local_smb_fname == NULL) {
2948 status = NT_STATUS_NO_MEMORY;
2952 /* Must use lstat here. */
2953 ret = SMB_VFS_LSTAT(fsp->conn, local_smb_fname);
2955 status = map_nt_error_from_unix(errno);
2959 /* Ensure it matches the fsp stat. */
2960 if (!check_same_stat(&local_smb_fname->st,
2961 &fsp->fsp_name->st)) {
2962 status = NT_STATUS_ACCESS_DENIED;
2966 ret = SMB_VFS_LCHOWN(fsp->conn,
2971 status = NT_STATUS_OK;
2973 status = map_nt_error_from_unix(errno);
2978 vfs_ChDir(fsp->conn, saved_dir_fname);
2979 TALLOC_FREE(local_smb_fname);
2980 TALLOC_FREE(saved_dir_fname);
2981 TALLOC_FREE(parent_dir);
2986 if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) {
2987 ret = SMB_VFS_LCHOWN(fsp->conn,
2991 ret = SMB_VFS_CHOWN(fsp->conn,
2997 status = NT_STATUS_OK;
2999 status = map_nt_error_from_unix(errno);
3004 int smb_vfs_call_chdir(struct vfs_handle_struct *handle,
3005 const struct smb_filename *smb_fname)
3008 return handle->fns->chdir_fn(handle, smb_fname);
3011 struct smb_filename *smb_vfs_call_getwd(struct vfs_handle_struct *handle,
3015 return handle->fns->getwd_fn(handle, ctx);
3018 int smb_vfs_call_ntimes(struct vfs_handle_struct *handle,
3019 const struct smb_filename *smb_fname,
3020 struct smb_file_time *ft)
3023 return handle->fns->ntimes_fn(handle, smb_fname, ft);
3026 int smb_vfs_call_ftruncate(struct vfs_handle_struct *handle,
3027 struct files_struct *fsp, off_t offset)
3029 VFS_FIND(ftruncate);
3030 return handle->fns->ftruncate_fn(handle, fsp, offset);
3033 int smb_vfs_call_fallocate(struct vfs_handle_struct *handle,
3034 struct files_struct *fsp,
3039 VFS_FIND(fallocate);
3040 return handle->fns->fallocate_fn(handle, fsp, mode, offset, len);
3043 int smb_vfs_call_kernel_flock(struct vfs_handle_struct *handle,
3044 struct files_struct *fsp, uint32_t share_mode,
3045 uint32_t access_mask)
3047 VFS_FIND(kernel_flock);
3048 return handle->fns->kernel_flock_fn(handle, fsp, share_mode,
3052 int smb_vfs_call_linux_setlease(struct vfs_handle_struct *handle,
3053 struct files_struct *fsp, int leasetype)
3055 VFS_FIND(linux_setlease);
3056 return handle->fns->linux_setlease_fn(handle, fsp, leasetype);
3059 int smb_vfs_call_symlink(struct vfs_handle_struct *handle,
3060 const char *link_target,
3061 const struct smb_filename *new_smb_fname)
3064 return handle->fns->symlink_fn(handle, link_target, new_smb_fname);
3067 int smb_vfs_call_readlink(struct vfs_handle_struct *handle,
3068 const struct smb_filename *smb_fname,
3073 return handle->fns->readlink_fn(handle, smb_fname, buf, bufsiz);
3076 int smb_vfs_call_link(struct vfs_handle_struct *handle,
3077 const struct smb_filename *old_smb_fname,
3078 const struct smb_filename *new_smb_fname)
3081 return handle->fns->link_fn(handle, old_smb_fname, new_smb_fname);
3084 int smb_vfs_call_mknod(struct vfs_handle_struct *handle,
3085 const struct smb_filename *smb_fname,
3090 return handle->fns->mknod_fn(handle, smb_fname, mode, dev);
3093 struct smb_filename *smb_vfs_call_realpath(struct vfs_handle_struct *handle,
3095 const struct smb_filename *smb_fname)
3098 return handle->fns->realpath_fn(handle, ctx, smb_fname);
3101 int smb_vfs_call_chflags(struct vfs_handle_struct *handle,
3102 const struct smb_filename *smb_fname,
3106 return handle->fns->chflags_fn(handle, smb_fname, flags);
3109 struct file_id smb_vfs_call_file_id_create(struct vfs_handle_struct *handle,
3110 const SMB_STRUCT_STAT *sbuf)
3112 VFS_FIND(file_id_create);
3113 return handle->fns->file_id_create_fn(handle, sbuf);
3116 NTSTATUS smb_vfs_call_streaminfo(struct vfs_handle_struct *handle,
3117 struct files_struct *fsp,
3118 const struct smb_filename *smb_fname,
3119 TALLOC_CTX *mem_ctx,
3120 unsigned int *num_streams,
3121 struct stream_struct **streams)
3123 VFS_FIND(streaminfo);
3124 return handle->fns->streaminfo_fn(handle, fsp, smb_fname, mem_ctx,
3125 num_streams, streams);
3128 int smb_vfs_call_get_real_filename(struct vfs_handle_struct *handle,
3129 const char *path, const char *name,
3130 TALLOC_CTX *mem_ctx, char **found_name)
3132 VFS_FIND(get_real_filename);
3133 return handle->fns->get_real_filename_fn(handle, path, name, mem_ctx,
3137 const char *smb_vfs_call_connectpath(struct vfs_handle_struct *handle,
3138 const struct smb_filename *smb_fname)
3140 VFS_FIND(connectpath);
3141 return handle->fns->connectpath_fn(handle, smb_fname);
3144 bool smb_vfs_call_strict_lock_check(struct vfs_handle_struct *handle,
3145 struct files_struct *fsp,
3146 struct lock_struct *plock)
3148 VFS_FIND(strict_lock_check);
3149 return handle->fns->strict_lock_check_fn(handle, fsp, plock);
3152 NTSTATUS smb_vfs_call_translate_name(struct vfs_handle_struct *handle,
3154 enum vfs_translate_direction direction,
3155 TALLOC_CTX *mem_ctx,
3158 VFS_FIND(translate_name);
3159 return handle->fns->translate_name_fn(handle, name, direction, mem_ctx,
3163 NTSTATUS smb_vfs_call_fsctl(struct vfs_handle_struct *handle,
3164 struct files_struct *fsp,
3168 const uint8_t *in_data,
3171 uint32_t max_out_len,
3175 return handle->fns->fsctl_fn(handle, fsp, ctx, function, req_flags,
3176 in_data, in_len, out_data, max_out_len,
3180 NTSTATUS smb_vfs_call_get_dos_attributes(struct vfs_handle_struct *handle,
3181 struct smb_filename *smb_fname,
3184 VFS_FIND(get_dos_attributes);
3185 return handle->fns->get_dos_attributes_fn(handle, smb_fname, dosmode);
3188 NTSTATUS smb_vfs_call_fget_dos_attributes(struct vfs_handle_struct *handle,
3189 struct files_struct *fsp,
3192 VFS_FIND(fget_dos_attributes);
3193 return handle->fns->fget_dos_attributes_fn(handle, fsp, dosmode);
3196 NTSTATUS smb_vfs_call_set_dos_attributes(struct vfs_handle_struct *handle,
3197 const struct smb_filename *smb_fname,
3200 VFS_FIND(set_dos_attributes);
3201 return handle->fns->set_dos_attributes_fn(handle, smb_fname, dosmode);
3204 NTSTATUS smb_vfs_call_fset_dos_attributes(struct vfs_handle_struct *handle,
3205 struct files_struct *fsp,
3208 VFS_FIND(set_dos_attributes);
3209 return handle->fns->fset_dos_attributes_fn(handle, fsp, dosmode);
3212 struct tevent_req *smb_vfs_call_offload_read_send(TALLOC_CTX *mem_ctx,
3213 struct tevent_context *ev,
3214 struct vfs_handle_struct *handle,
3215 struct files_struct *fsp,
3221 VFS_FIND(offload_read_send);
3222 return handle->fns->offload_read_send_fn(mem_ctx, ev, handle,
3224 ttl, offset, to_copy);
3227 NTSTATUS smb_vfs_call_offload_read_recv(struct tevent_req *req,
3228 struct vfs_handle_struct *handle,
3229 TALLOC_CTX *mem_ctx,
3230 DATA_BLOB *token_blob)
3232 VFS_FIND(offload_read_recv);
3233 return handle->fns->offload_read_recv_fn(req, handle, mem_ctx, token_blob);
3236 struct tevent_req *smb_vfs_call_offload_write_send(struct vfs_handle_struct *handle,
3237 TALLOC_CTX *mem_ctx,
3238 struct tevent_context *ev,
3241 off_t transfer_offset,
3242 struct files_struct *dest_fsp,
3246 VFS_FIND(offload_write_send);
3247 return handle->fns->offload_write_send_fn(handle, mem_ctx, ev, fsctl,
3248 token, transfer_offset,
3249 dest_fsp, dest_off, num);
3252 NTSTATUS smb_vfs_call_offload_write_recv(struct vfs_handle_struct *handle,
3253 struct tevent_req *req,
3256 VFS_FIND(offload_write_recv);
3257 return handle->fns->offload_write_recv_fn(handle, req, copied);
3260 struct smb_vfs_call_get_dos_attributes_state {
3261 NTSTATUS (*recv_fn)(struct tevent_req *req,
3262 struct vfs_aio_state *aio_state,
3264 struct vfs_aio_state aio_state;
3265 uint32_t dos_attributes;
3268 static void smb_vfs_call_get_dos_attributes_done(struct tevent_req *subreq);
3270 struct tevent_req *smb_vfs_call_get_dos_attributes_send(
3271 TALLOC_CTX *mem_ctx,
3272 const struct smb_vfs_ev_glue *evg,
3273 struct vfs_handle_struct *handle,
3274 files_struct *dir_fsp,
3275 struct smb_filename *smb_fname)
3277 struct tevent_req *req = NULL;
3278 struct smb_vfs_call_get_dos_attributes_state *state = NULL;
3279 struct tevent_req *subreq = NULL;
3282 req = tevent_req_create(mem_ctx, &state,
3283 struct smb_vfs_call_get_dos_attributes_state);
3288 VFS_FIND(get_dos_attributes_send);
3289 state->recv_fn = handle->fns->get_dos_attributes_recv_fn;
3291 ok = smb_vfs_ev_glue_push_use(evg, req);
3293 tevent_req_error(req, EIO);
3294 return tevent_req_post(req, evg->return_ev);
3297 subreq = handle->fns->get_dos_attributes_send_fn(mem_ctx,
3302 smb_vfs_ev_glue_pop_use(evg);
3304 if (tevent_req_nomem(subreq, req)) {
3305 return tevent_req_post(req, evg->return_ev);
3307 tevent_req_set_callback(subreq,
3308 smb_vfs_call_get_dos_attributes_done,
3314 static void smb_vfs_call_get_dos_attributes_done(struct tevent_req *subreq)
3316 struct tevent_req *req =
3317 tevent_req_callback_data(subreq,
3319 struct smb_vfs_call_get_dos_attributes_state *state =
3320 tevent_req_data(req,
3321 struct smb_vfs_call_get_dos_attributes_state);
3324 status = state->recv_fn(subreq,
3326 &state->dos_attributes);
3327 TALLOC_FREE(subreq);
3328 if (tevent_req_nterror(req, status)) {
3332 tevent_req_done(req);
3335 NTSTATUS smb_vfs_call_get_dos_attributes_recv(
3336 struct tevent_req *req,
3337 struct vfs_aio_state *aio_state,
3338 uint32_t *dos_attributes)
3340 struct smb_vfs_call_get_dos_attributes_state *state =
3341 tevent_req_data(req,
3342 struct smb_vfs_call_get_dos_attributes_state);
3345 if (tevent_req_is_nterror(req, &status)) {
3346 tevent_req_received(req);
3350 *aio_state = state->aio_state;
3351 *dos_attributes = state->dos_attributes;
3352 tevent_req_received(req);
3353 return NT_STATUS_OK;
3356 NTSTATUS smb_vfs_call_get_compression(vfs_handle_struct *handle,
3357 TALLOC_CTX *mem_ctx,
3358 struct files_struct *fsp,
3359 struct smb_filename *smb_fname,
3360 uint16_t *_compression_fmt)
3362 VFS_FIND(get_compression);
3363 return handle->fns->get_compression_fn(handle, mem_ctx, fsp, smb_fname,
3367 NTSTATUS smb_vfs_call_set_compression(vfs_handle_struct *handle,
3368 TALLOC_CTX *mem_ctx,
3369 struct files_struct *fsp,
3370 uint16_t compression_fmt)
3372 VFS_FIND(set_compression);
3373 return handle->fns->set_compression_fn(handle, mem_ctx, fsp,
3377 NTSTATUS smb_vfs_call_snap_check_path(vfs_handle_struct *handle,
3378 TALLOC_CTX *mem_ctx,
3379 const char *service_path,
3382 VFS_FIND(snap_check_path);
3383 return handle->fns->snap_check_path_fn(handle, mem_ctx, service_path,
3387 NTSTATUS smb_vfs_call_snap_create(struct vfs_handle_struct *handle,
3388 TALLOC_CTX *mem_ctx,
3389 const char *base_volume,
3395 VFS_FIND(snap_create);
3396 return handle->fns->snap_create_fn(handle, mem_ctx, base_volume, tstamp,
3397 rw, base_path, snap_path);
3400 NTSTATUS smb_vfs_call_snap_delete(struct vfs_handle_struct *handle,
3401 TALLOC_CTX *mem_ctx,
3405 VFS_FIND(snap_delete);
3406 return handle->fns->snap_delete_fn(handle, mem_ctx, base_path,
3410 NTSTATUS smb_vfs_call_fget_nt_acl(struct vfs_handle_struct *handle,
3411 struct files_struct *fsp,
3412 uint32_t security_info,
3413 TALLOC_CTX *mem_ctx,
3414 struct security_descriptor **ppdesc)
3416 VFS_FIND(fget_nt_acl);
3417 return handle->fns->fget_nt_acl_fn(handle, fsp, security_info,
3421 NTSTATUS smb_vfs_call_get_nt_acl(struct vfs_handle_struct *handle,
3422 const struct smb_filename *smb_fname,
3423 uint32_t security_info,
3424 TALLOC_CTX *mem_ctx,
3425 struct security_descriptor **ppdesc)
3427 VFS_FIND(get_nt_acl);
3428 return handle->fns->get_nt_acl_fn(handle,
3435 NTSTATUS smb_vfs_call_fset_nt_acl(struct vfs_handle_struct *handle,
3436 struct files_struct *fsp,
3437 uint32_t security_info_sent,
3438 const struct security_descriptor *psd)
3440 VFS_FIND(fset_nt_acl);
3441 return handle->fns->fset_nt_acl_fn(handle, fsp, security_info_sent,
3445 NTSTATUS smb_vfs_call_audit_file(struct vfs_handle_struct *handle,
3446 struct smb_filename *file,
3447 struct security_acl *sacl,
3448 uint32_t access_requested,
3449 uint32_t access_denied)
3451 VFS_FIND(audit_file);
3452 return handle->fns->audit_file_fn(handle,
3459 SMB_ACL_T smb_vfs_call_sys_acl_get_file(struct vfs_handle_struct *handle,
3460 const struct smb_filename *smb_fname,
3461 SMB_ACL_TYPE_T type,
3462 TALLOC_CTX *mem_ctx)
3464 VFS_FIND(sys_acl_get_file);
3465 return handle->fns->sys_acl_get_file_fn(handle, smb_fname, type, mem_ctx);
3468 SMB_ACL_T smb_vfs_call_sys_acl_get_fd(struct vfs_handle_struct *handle,
3469 struct files_struct *fsp,
3470 TALLOC_CTX *mem_ctx)
3472 VFS_FIND(sys_acl_get_fd);
3473 return handle->fns->sys_acl_get_fd_fn(handle, fsp, mem_ctx);
3476 int smb_vfs_call_sys_acl_blob_get_file(struct vfs_handle_struct *handle,
3477 const struct smb_filename *smb_fname,
3478 TALLOC_CTX *mem_ctx,
3479 char **blob_description,
3482 VFS_FIND(sys_acl_blob_get_file);
3483 return handle->fns->sys_acl_blob_get_file_fn(handle, smb_fname,
3484 mem_ctx, blob_description, blob);
3487 int smb_vfs_call_sys_acl_blob_get_fd(struct vfs_handle_struct *handle,
3488 struct files_struct *fsp,
3489 TALLOC_CTX *mem_ctx,
3490 char **blob_description,
3493 VFS_FIND(sys_acl_blob_get_fd);
3494 return handle->fns->sys_acl_blob_get_fd_fn(handle, fsp, mem_ctx, blob_description, blob);
3497 int smb_vfs_call_sys_acl_set_file(struct vfs_handle_struct *handle,
3498 const struct smb_filename *smb_fname,
3499 SMB_ACL_TYPE_T acltype,
3502 VFS_FIND(sys_acl_set_file);
3503 return handle->fns->sys_acl_set_file_fn(handle, smb_fname,
3507 int smb_vfs_call_sys_acl_set_fd(struct vfs_handle_struct *handle,
3508 struct files_struct *fsp, SMB_ACL_T theacl)
3510 VFS_FIND(sys_acl_set_fd);
3511 return handle->fns->sys_acl_set_fd_fn(handle, fsp, theacl);
3514 int smb_vfs_call_sys_acl_delete_def_file(struct vfs_handle_struct *handle,
3515 const struct smb_filename *smb_fname)
3517 VFS_FIND(sys_acl_delete_def_file);
3518 return handle->fns->sys_acl_delete_def_file_fn(handle, smb_fname);
3521 ssize_t smb_vfs_call_getxattr(struct vfs_handle_struct *handle,
3522 const struct smb_filename *smb_fname,
3528 return handle->fns->getxattr_fn(handle, smb_fname, name, value, size);
3532 struct smb_vfs_call_getxattrat_state {
3533 ssize_t (*recv_fn)(struct tevent_req *req,
3534 struct vfs_aio_state *aio_state,
3535 TALLOC_CTX *mem_ctx,
3536 uint8_t **xattr_value);
3538 uint8_t *xattr_value;
3539 struct vfs_aio_state aio_state;
3542 static void smb_vfs_call_getxattrat_done(struct tevent_req *subreq);
3544 struct tevent_req *smb_vfs_call_getxattrat_send(
3545 TALLOC_CTX *mem_ctx,
3546 const struct smb_vfs_ev_glue *evg,
3547 struct vfs_handle_struct *handle,
3548 files_struct *dir_fsp,
3549 const struct smb_filename *smb_fname,
3550 const char *xattr_name,
3553 struct tevent_req *req = NULL;
3554 struct smb_vfs_call_getxattrat_state *state = NULL;
3555 struct tevent_req *subreq = NULL;
3558 req = tevent_req_create(mem_ctx, &state,
3559 struct smb_vfs_call_getxattrat_state);
3564 VFS_FIND(getxattrat_send);
3565 state->recv_fn = handle->fns->getxattrat_recv_fn;
3567 ok = smb_vfs_ev_glue_push_use(evg, req);
3569 tevent_req_error(req, EIO);
3570 return tevent_req_post(req, evg->return_ev);
3573 subreq = handle->fns->getxattrat_send_fn(mem_ctx,
3580 smb_vfs_ev_glue_pop_use(evg);
3582 if (tevent_req_nomem(subreq, req)) {
3583 return tevent_req_post(req, evg->return_ev);
3585 tevent_req_set_callback(subreq, smb_vfs_call_getxattrat_done, req);
3589 static void smb_vfs_call_getxattrat_done(struct tevent_req *subreq)
3591 struct tevent_req *req = tevent_req_callback_data(
3592 subreq, struct tevent_req);
3593 struct smb_vfs_call_getxattrat_state *state = tevent_req_data(
3594 req, struct smb_vfs_call_getxattrat_state);
3596 state->retval = state->recv_fn(subreq,
3599 &state->xattr_value);
3600 TALLOC_FREE(subreq);
3601 if (state->retval == -1) {
3602 tevent_req_error(req, state->aio_state.error);
3606 tevent_req_done(req);
3609 ssize_t smb_vfs_call_getxattrat_recv(struct tevent_req *req,
3610 struct vfs_aio_state *aio_state,
3611 TALLOC_CTX *mem_ctx,
3612 uint8_t **xattr_value)
3614 struct smb_vfs_call_getxattrat_state *state = tevent_req_data(
3615 req, struct smb_vfs_call_getxattrat_state);
3618 if (tevent_req_is_unix_error(req, &aio_state->error)) {
3619 tevent_req_received(req);
3623 *aio_state = state->aio_state;
3624 xattr_size = state->retval;
3625 if (xattr_value != NULL) {
3626 *xattr_value = talloc_move(mem_ctx, &state->xattr_value);
3629 tevent_req_received(req);
3633 ssize_t smb_vfs_call_fgetxattr(struct vfs_handle_struct *handle,
3634 struct files_struct *fsp, const char *name,
3635 void *value, size_t size)
3637 VFS_FIND(fgetxattr);
3638 return handle->fns->fgetxattr_fn(handle, fsp, name, value, size);
3641 ssize_t smb_vfs_call_listxattr(struct vfs_handle_struct *handle,
3642 const struct smb_filename *smb_fname,
3646 VFS_FIND(listxattr);
3647 return handle->fns->listxattr_fn(handle, smb_fname, list, size);
3650 ssize_t smb_vfs_call_flistxattr(struct vfs_handle_struct *handle,
3651 struct files_struct *fsp, char *list,
3654 VFS_FIND(flistxattr);
3655 return handle->fns->flistxattr_fn(handle, fsp, list, size);
3658 int smb_vfs_call_removexattr(struct vfs_handle_struct *handle,
3659 const struct smb_filename *smb_fname,
3662 VFS_FIND(removexattr);
3663 return handle->fns->removexattr_fn(handle, smb_fname, name);
3666 int smb_vfs_call_fremovexattr(struct vfs_handle_struct *handle,
3667 struct files_struct *fsp, const char *name)
3669 VFS_FIND(fremovexattr);
3670 return handle->fns->fremovexattr_fn(handle, fsp, name);
3673 int smb_vfs_call_setxattr(struct vfs_handle_struct *handle,
3674 const struct smb_filename *smb_fname,
3681 return handle->fns->setxattr_fn(handle, smb_fname,
3682 name, value, size, flags);
3685 int smb_vfs_call_fsetxattr(struct vfs_handle_struct *handle,
3686 struct files_struct *fsp, const char *name,
3687 const void *value, size_t size, int flags)
3689 VFS_FIND(fsetxattr);
3690 return handle->fns->fsetxattr_fn(handle, fsp, name, value, size, flags);
3693 bool smb_vfs_call_aio_force(struct vfs_handle_struct *handle,
3694 struct files_struct *fsp)
3696 VFS_FIND(aio_force);
3697 return handle->fns->aio_force_fn(handle, fsp);
3700 NTSTATUS smb_vfs_call_durable_cookie(struct vfs_handle_struct *handle,
3701 struct files_struct *fsp,
3702 TALLOC_CTX *mem_ctx,
3705 VFS_FIND(durable_cookie);
3706 return handle->fns->durable_cookie_fn(handle, fsp, mem_ctx, cookie);
3709 NTSTATUS smb_vfs_call_durable_disconnect(struct vfs_handle_struct *handle,
3710 struct files_struct *fsp,
3711 const DATA_BLOB old_cookie,
3712 TALLOC_CTX *mem_ctx,
3713 DATA_BLOB *new_cookie)
3715 VFS_FIND(durable_disconnect);
3716 return handle->fns->durable_disconnect_fn(handle, fsp, old_cookie,
3717 mem_ctx, new_cookie);
3720 NTSTATUS smb_vfs_call_durable_reconnect(struct vfs_handle_struct *handle,
3721 struct smb_request *smb1req,
3722 struct smbXsrv_open *op,
3723 const DATA_BLOB old_cookie,
3724 TALLOC_CTX *mem_ctx,
3725 struct files_struct **fsp,
3726 DATA_BLOB *new_cookie)
3728 VFS_FIND(durable_reconnect);
3729 return handle->fns->durable_reconnect_fn(handle, smb1req, op,
3730 old_cookie, mem_ctx, fsp,
3734 NTSTATUS smb_vfs_call_readdir_attr(struct vfs_handle_struct *handle,
3735 const struct smb_filename *fname,
3736 TALLOC_CTX *mem_ctx,
3737 struct readdir_attr_data **attr_data)
3739 VFS_FIND(readdir_attr);
3740 return handle->fns->readdir_attr_fn(handle, fname, mem_ctx, attr_data);