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)
790 struct smb_filename *old_cwd = conn->cwd_fname;
793 LastDir = SMB_STRDUP("");
796 if (ISDOT(smb_fname->base_name)) {
800 if (*smb_fname->base_name == '/' &&
801 strcsequal(LastDir,smb_fname->base_name)) {
805 DEBUG(4,("vfs_ChDir to %s\n", smb_fname->base_name));
807 ret = SMB_VFS_CHDIR(conn, smb_fname);
813 * Always replace conn->cwd_fname. We
814 * don't know if it's been modified by
815 * VFS modules in the stack.
819 conn->cwd_fname = vfs_GetWd(conn, conn);
820 if (conn->cwd_fname == NULL) {
822 * vfs_GetWd() failed.
823 * We must be able to read cwd.
824 * Return to original directory
827 int saved_errno = errno;
829 if (old_cwd == NULL) {
831 * Failed on the very first chdir()+getwd()
832 * for this connection. We can't
835 smb_panic("conn->cwd getwd failed\n");
839 /* Restore original conn->cwd_fname. */
840 conn->cwd_fname = old_cwd;
842 /* Return to the previous $cwd. */
843 ret = SMB_VFS_CHDIR(conn, conn->cwd_fname);
845 smb_panic("conn->cwd getwd failed\n");
850 /* And fail the chdir(). */
854 /* vfs_GetWd() succeeded. */
855 /* Replace global cache. */
857 LastDir = SMB_STRDUP(smb_fname->base_name);
859 DEBUG(4,("vfs_ChDir got %s\n", conn->cwd_fname->base_name));
861 TALLOC_FREE(old_cwd);
865 /*******************************************************************
866 Return the absolute current directory path - given a UNIX pathname.
867 Note that this path is returned in DOS format, not UNIX
868 format. Note this can be called with conn == NULL.
869 ********************************************************************/
871 struct smb_filename *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn)
873 struct smb_filename *current_dir_fname = NULL;
875 struct smb_filename *smb_fname_dot = NULL;
876 struct smb_filename *smb_fname_full = NULL;
877 struct smb_filename *result = NULL;
879 if (!lp_getwd_cache()) {
883 smb_fname_dot = synthetic_smb_fname(ctx, ".", NULL, NULL, 0);
884 if (smb_fname_dot == NULL) {
889 if (SMB_VFS_STAT(conn, smb_fname_dot) == -1) {
891 * Known to fail for root: the directory may be NFS-mounted
892 * and exported with root_squash (so has no root access).
894 DEBUG(1,("vfs_GetWd: couldn't stat \".\" error %s "
895 "(NFS problem ?)\n", strerror(errno) ));
899 key = vfs_file_id_from_sbuf(conn, &smb_fname_dot->st);
901 smb_fname_full = (struct smb_filename *)memcache_lookup_talloc(
904 data_blob_const(&key, sizeof(key)));
906 if (smb_fname_full == NULL) {
910 if ((SMB_VFS_STAT(conn, smb_fname_full) == 0) &&
911 (smb_fname_dot->st.st_ex_dev == smb_fname_full->st.st_ex_dev) &&
912 (smb_fname_dot->st.st_ex_ino == smb_fname_full->st.st_ex_ino) &&
913 (S_ISDIR(smb_fname_dot->st.st_ex_mode))) {
916 * Note: smb_fname_full is owned by smbd_memcache()
917 * so we must make a copy to return.
919 result = cp_smb_filename(ctx, smb_fname_full);
920 if (result == NULL) {
929 * We don't have the information to hand so rely on traditional
930 * methods. The very slow getcwd, which spawns a process on some
931 * systems, or the not quite so bad getwd.
934 current_dir_fname = SMB_VFS_GETWD(conn, ctx);
935 if (current_dir_fname == NULL) {
936 DEBUG(0, ("vfs_GetWd: SMB_VFS_GETWD call failed: %s\n",
941 if (lp_getwd_cache() && VALID_STAT(smb_fname_dot->st)) {
942 key = vfs_file_id_from_sbuf(conn, &smb_fname_dot->st);
945 * smbd_memcache() will own current_dir_fname after the
946 * memcache_add_talloc call, so we must make
947 * a copy on ctx to return.
949 result = cp_smb_filename(ctx, current_dir_fname);
950 if (result == NULL) {
955 * Ensure the memory going into the cache
956 * doesn't have a destructor so it can be
959 talloc_set_destructor(current_dir_fname, NULL);
961 memcache_add_talloc(smbd_memcache(),
963 data_blob_const(&key, sizeof(key)),
965 /* current_dir_fname is now == NULL here. */
967 /* current_dir_fname is already allocated on ctx. */
968 result = current_dir_fname;
972 TALLOC_FREE(smb_fname_dot);
974 * Don't free current_dir_fname here. It's either been moved
975 * to the memcache or is being returned in result.
980 /*******************************************************************
981 Reduce a file name, removing .. elements and checking that
982 it is below dir in the hierarchy. This uses realpath.
983 This function must run as root, and will return names
984 and valid stat structs that can be checked on open.
985 ********************************************************************/
987 NTSTATUS check_reduced_name_with_privilege(connection_struct *conn,
988 const struct smb_filename *smb_fname,
989 struct smb_request *smbreq)
992 TALLOC_CTX *ctx = talloc_tos();
993 const char *conn_rootdir;
995 char *dir_name = NULL;
996 char *resolved_name = NULL;
997 const char *last_component = NULL;
998 struct smb_filename *resolved_fname = NULL;
999 struct smb_filename *saved_dir_fname = NULL;
1000 struct smb_filename *smb_fname_cwd = NULL;
1001 struct privilege_paths *priv_paths = NULL;
1004 DEBUG(3,("check_reduced_name_with_privilege [%s] [%s]\n",
1005 smb_fname->base_name,
1006 conn->connectpath));
1009 priv_paths = talloc_zero(smbreq, struct privilege_paths);
1011 status = NT_STATUS_NO_MEMORY;
1015 if (!parent_dirname(ctx, smb_fname->base_name,
1016 &dir_name, &last_component)) {
1017 status = NT_STATUS_NO_MEMORY;
1021 priv_paths->parent_name.base_name = talloc_strdup(priv_paths, dir_name);
1022 priv_paths->file_name.base_name = talloc_strdup(priv_paths, last_component);
1024 if (priv_paths->parent_name.base_name == NULL ||
1025 priv_paths->file_name.base_name == NULL) {
1026 status = NT_STATUS_NO_MEMORY;
1030 if (SMB_VFS_STAT(conn, &priv_paths->parent_name) != 0) {
1031 status = map_nt_error_from_unix(errno);
1034 /* Remember where we were. */
1035 saved_dir_fname = vfs_GetWd(ctx, conn);
1036 if (!saved_dir_fname) {
1037 status = map_nt_error_from_unix(errno);
1041 if (vfs_ChDir(conn, &priv_paths->parent_name) == -1) {
1042 status = map_nt_error_from_unix(errno);
1046 smb_fname_cwd = synthetic_smb_fname(talloc_tos(), ".", NULL, NULL, 0);
1047 if (smb_fname_cwd == NULL) {
1048 status = NT_STATUS_NO_MEMORY;
1052 /* Get the absolute path of the parent directory. */
1053 resolved_fname = SMB_VFS_REALPATH(conn, ctx, smb_fname_cwd);
1054 if (resolved_fname == NULL) {
1055 status = map_nt_error_from_unix(errno);
1058 resolved_name = resolved_fname->base_name;
1060 if (*resolved_name != '/') {
1061 DEBUG(0,("check_reduced_name_with_privilege: realpath "
1062 "doesn't return absolute paths !\n"));
1063 status = NT_STATUS_OBJECT_NAME_INVALID;
1067 DEBUG(10,("check_reduced_name_with_privilege: realpath [%s] -> [%s]\n",
1068 priv_paths->parent_name.base_name,
1071 /* Now check the stat value is the same. */
1072 if (SMB_VFS_LSTAT(conn, smb_fname_cwd) != 0) {
1073 status = map_nt_error_from_unix(errno);
1077 /* Ensure we're pointing at the same place. */
1078 if (!check_same_stat(&smb_fname_cwd->st, &priv_paths->parent_name.st)) {
1079 DEBUG(0,("check_reduced_name_with_privilege: "
1080 "device/inode/uid/gid on directory %s changed. "
1081 "Denying access !\n",
1082 priv_paths->parent_name.base_name));
1083 status = NT_STATUS_ACCESS_DENIED;
1087 /* Ensure we're below the connect path. */
1089 conn_rootdir = SMB_VFS_CONNECTPATH(conn, smb_fname);
1090 if (conn_rootdir == NULL) {
1091 DEBUG(2, ("check_reduced_name_with_privilege: Could not get "
1093 status = NT_STATUS_ACCESS_DENIED;
1097 rootdir_len = strlen(conn_rootdir);
1100 * In the case of rootdir_len == 1, we know that conn_rootdir is
1101 * "/", and we also know that resolved_name starts with a slash.
1102 * So, in this corner case, resolved_name is automatically a
1103 * sub-directory of the conn_rootdir. Thus we can skip the string
1104 * comparison and the next character checks (which are even
1105 * wrong in this case).
1107 if (rootdir_len != 1) {
1110 matched = (strncmp(conn_rootdir, resolved_name,
1113 if (!matched || (resolved_name[rootdir_len] != '/' &&
1114 resolved_name[rootdir_len] != '\0')) {
1115 DEBUG(2, ("check_reduced_name_with_privilege: Bad "
1116 "access attempt: %s is a symlink outside the "
1119 DEBUGADD(2, ("conn_rootdir =%s\n", conn_rootdir));
1120 DEBUGADD(2, ("resolved_name=%s\n", resolved_name));
1121 status = NT_STATUS_ACCESS_DENIED;
1126 /* Now ensure that the last component either doesn't
1127 exist, or is *NOT* a symlink. */
1129 ret = SMB_VFS_LSTAT(conn, &priv_paths->file_name);
1131 /* Errno must be ENOENT for this be ok. */
1132 if (errno != ENOENT) {
1133 status = map_nt_error_from_unix(errno);
1134 DEBUG(2, ("check_reduced_name_with_privilege: "
1135 "LSTAT on %s failed with %s\n",
1136 priv_paths->file_name.base_name,
1137 nt_errstr(status)));
1142 if (VALID_STAT(priv_paths->file_name.st) &&
1143 S_ISLNK(priv_paths->file_name.st.st_ex_mode)) {
1144 DEBUG(2, ("check_reduced_name_with_privilege: "
1145 "Last component %s is a symlink. Denying"
1147 priv_paths->file_name.base_name));
1148 status = NT_STATUS_ACCESS_DENIED;
1152 smbreq->priv_paths = priv_paths;
1153 status = NT_STATUS_OK;
1157 if (saved_dir_fname != NULL) {
1158 vfs_ChDir(conn, saved_dir_fname);
1159 TALLOC_FREE(saved_dir_fname);
1161 TALLOC_FREE(resolved_fname);
1162 if (!NT_STATUS_IS_OK(status)) {
1163 TALLOC_FREE(priv_paths);
1165 TALLOC_FREE(dir_name);
1169 /*******************************************************************
1170 Reduce a file name, removing .. elements and checking that
1171 it is below dir in the hierarchy. This uses realpath.
1173 If cwd_name == NULL then fname is a client given path relative
1174 to the root path of the share.
1176 If cwd_name != NULL then fname is a client given path relative
1177 to cwd_name. cwd_name is relative to the root path of the share.
1178 ********************************************************************/
1180 NTSTATUS check_reduced_name(connection_struct *conn,
1181 const struct smb_filename *cwd_fname,
1182 const struct smb_filename *smb_fname)
1184 TALLOC_CTX *ctx = talloc_tos();
1185 const char *cwd_name = cwd_fname ? cwd_fname->base_name : NULL;
1186 const char *fname = smb_fname->base_name;
1187 struct smb_filename *resolved_fname;
1188 char *resolved_name = NULL;
1189 char *new_fname = NULL;
1190 bool allow_symlinks = true;
1191 bool allow_widelinks = false;
1193 DBG_DEBUG("check_reduced_name [%s] [%s]\n", fname, conn->connectpath);
1195 resolved_fname = SMB_VFS_REALPATH(conn, ctx, smb_fname);
1197 if (resolved_fname == NULL) {
1200 DEBUG(3,("check_reduced_name: Component not a "
1201 "directory in getting realpath for "
1203 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1206 char *dir_name = NULL;
1207 struct smb_filename dir_fname = {0};
1208 const char *last_component = NULL;
1210 /* Last component didn't exist.
1211 Remove it and try and canonicalise
1212 the directory name. */
1213 if (!parent_dirname(ctx, fname,
1216 return NT_STATUS_NO_MEMORY;
1219 dir_fname = (struct smb_filename)
1220 { .base_name = dir_name };
1221 resolved_fname = SMB_VFS_REALPATH(conn,
1224 if (resolved_fname == NULL) {
1225 NTSTATUS status = map_nt_error_from_unix(errno);
1227 if (errno == ENOENT || errno == ENOTDIR) {
1228 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1231 DEBUG(3,("check_reduce_name: "
1232 "couldn't get realpath for "
1235 nt_errstr(status)));
1238 resolved_name = talloc_asprintf(ctx,
1240 resolved_fname->base_name,
1242 if (resolved_name == NULL) {
1243 return NT_STATUS_NO_MEMORY;
1248 DEBUG(3,("check_reduced_name: couldn't get "
1249 "realpath for %s\n", fname));
1250 return map_nt_error_from_unix(errno);
1253 resolved_name = resolved_fname->base_name;
1256 DEBUG(10,("check_reduced_name realpath [%s] -> [%s]\n", fname,
1259 if (*resolved_name != '/') {
1260 DEBUG(0,("check_reduced_name: realpath doesn't return "
1261 "absolute paths !\n"));
1262 TALLOC_FREE(resolved_fname);
1263 return NT_STATUS_OBJECT_NAME_INVALID;
1266 allow_widelinks = lp_widelinks(SNUM(conn));
1267 allow_symlinks = lp_follow_symlinks(SNUM(conn));
1269 /* Common widelinks and symlinks checks. */
1270 if (!allow_widelinks || !allow_symlinks) {
1271 const char *conn_rootdir;
1274 conn_rootdir = SMB_VFS_CONNECTPATH(conn, smb_fname);
1275 if (conn_rootdir == NULL) {
1276 DEBUG(2, ("check_reduced_name: Could not get "
1278 TALLOC_FREE(resolved_fname);
1279 return NT_STATUS_ACCESS_DENIED;
1282 rootdir_len = strlen(conn_rootdir);
1285 * In the case of rootdir_len == 1, we know that
1286 * conn_rootdir is "/", and we also know that
1287 * resolved_name starts with a slash. So, in this
1288 * corner case, resolved_name is automatically a
1289 * sub-directory of the conn_rootdir. Thus we can skip
1290 * the string comparison and the next character checks
1291 * (which are even wrong in this case).
1293 if (rootdir_len != 1) {
1296 matched = (strncmp(conn_rootdir, resolved_name,
1298 if (!matched || (resolved_name[rootdir_len] != '/' &&
1299 resolved_name[rootdir_len] != '\0')) {
1300 DEBUG(2, ("check_reduced_name: Bad access "
1301 "attempt: %s is a symlink outside the "
1302 "share path\n", fname));
1303 DEBUGADD(2, ("conn_rootdir =%s\n",
1305 DEBUGADD(2, ("resolved_name=%s\n",
1307 TALLOC_FREE(resolved_fname);
1308 return NT_STATUS_ACCESS_DENIED;
1312 /* Extra checks if all symlinks are disallowed. */
1313 if (!allow_symlinks) {
1314 /* fname can't have changed in resolved_path. */
1315 const char *p = &resolved_name[rootdir_len];
1318 * UNIX filesystem semantics, names consisting
1319 * only of "." or ".." CANNOT be symlinks.
1321 if (ISDOT(fname) || ISDOTDOT(fname)) {
1326 DEBUG(2, ("check_reduced_name: logic error (%c) "
1327 "in resolved_name: %s\n",
1330 TALLOC_FREE(resolved_fname);
1331 return NT_STATUS_ACCESS_DENIED;
1337 * If cwd_name is present and not ".",
1338 * then fname is relative to that, not
1339 * the root of the share. Make sure the
1340 * path we check is the one the client
1341 * sent (cwd_name+fname).
1343 if (cwd_name != NULL && !ISDOT(cwd_name)) {
1344 new_fname = talloc_asprintf(ctx,
1348 if (new_fname == NULL) {
1349 TALLOC_FREE(resolved_fname);
1350 return NT_STATUS_NO_MEMORY;
1355 if (strcmp(fname, p)!=0) {
1356 DEBUG(2, ("check_reduced_name: Bad access "
1357 "attempt: %s is a symlink to %s\n",
1359 TALLOC_FREE(resolved_fname);
1360 TALLOC_FREE(new_fname);
1361 return NT_STATUS_ACCESS_DENIED;
1368 DBG_INFO("%s reduced to %s\n", fname, resolved_name);
1369 TALLOC_FREE(resolved_fname);
1370 TALLOC_FREE(new_fname);
1371 return NT_STATUS_OK;
1375 * XXX: This is temporary and there should be no callers of this once
1376 * smb_filename is plumbed through all path based operations.
1378 * Called when we know stream name parsing has already been done.
1380 int vfs_stat_smb_basename(struct connection_struct *conn,
1381 const struct smb_filename *smb_fname_in,
1382 SMB_STRUCT_STAT *psbuf)
1384 struct smb_filename smb_fname = {
1385 .base_name = discard_const_p(char, smb_fname_in->base_name),
1386 .flags = smb_fname_in->flags
1390 if (smb_fname.flags & SMB_FILENAME_POSIX_PATH) {
1391 ret = SMB_VFS_LSTAT(conn, &smb_fname);
1393 ret = SMB_VFS_STAT(conn, &smb_fname);
1397 *psbuf = smb_fname.st;
1403 * Ensure LSTAT is called for POSIX paths.
1406 NTSTATUS vfs_stat_fsp(files_struct *fsp)
1410 if(fsp->fh->fd == -1) {
1411 if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) {
1412 ret = SMB_VFS_LSTAT(fsp->conn, fsp->fsp_name);
1414 ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name);
1417 return map_nt_error_from_unix(errno);
1420 if(SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st) != 0) {
1421 return map_nt_error_from_unix(errno);
1424 return NT_STATUS_OK;
1428 * Initialize num_streams and streams, then call VFS op streaminfo
1430 NTSTATUS vfs_streaminfo(connection_struct *conn,
1431 struct files_struct *fsp,
1432 const struct smb_filename *smb_fname,
1433 TALLOC_CTX *mem_ctx,
1434 unsigned int *num_streams,
1435 struct stream_struct **streams)
1439 return SMB_VFS_STREAMINFO(conn,
1448 generate a file_id from a stat structure
1450 struct file_id vfs_file_id_from_sbuf(connection_struct *conn, const SMB_STRUCT_STAT *sbuf)
1452 return SMB_VFS_FILE_ID_CREATE(conn, sbuf);
1456 * Design of the smb_vfs_ev_glue infrastructure:
1458 * smb_vfs_ev_glue makes it possible to pass
1459 * down an tevent_context and pthreadpool_tevent
1460 * used for impersonation through the SMB_VFS stack.
1462 * tevent_req based function take an tevent_context as
1463 * there 2nd argument, e.g.:
1465 * struct tevent_req *something_send(TALLOC_CTX *mem_ctx,
1466 * struct tevent_context *ev,
1469 * For the SMB_VFS stack we'll use the following:
1471 * struct tevent_req *SMB_VFS_SOMETHING_SEND(TALLOC_CTX *mem_ctx,
1472 * const struct smb_vfs_ev_glue *evg,
1475 * Typically the 'evg' is just passed through the stack down
1476 * to vfs_default.c. In order to do real work an
1477 * tevent_context and pthreadpool_tevent are required
1478 * to do call a 'somthing()' syscall in an async fashion.
1479 * Therefore it will the following to get the pointer
1482 * ev = smb_vfs_ev_glue_ev_ctx(evg);
1483 * tp = smb_vfs_ev_glue_tp_chdir_safe(evg);
1485 * If some function in the stack is sure it needs to run as root
1486 * to get some information (after careful checks!), it used
1487 * to frame that work into become_root()/unbecome_root().
1488 * This can't work when using async functions!
1489 * Now it's possible to use something like this (simplified!):
1491 * ev = smb_vfs_ev_glue_ev_ctx(evg);
1492 * root_evg = smb_vfs_ev_glue_get_root_glue(evg);
1493 * subreq = SMB_VFS_SOMETHING_NEXT_SEND(state, root_evg, ...);
1494 * if (tevent_req_nomem(subreq, req)) {
1495 * return tevent_req_post(req, ev);
1497 * tevent_req_set_callback(subreq, module_something_done, req);
1501 * static void module_something_done(struct tevent_req *subreq)
1505 * status = SMB_VFS_SOMETHING_NEXT_RECV(subreq, &state->aio_state);
1506 * TALLOC_FREE(subreq);
1508 * tevent_req_done(req);
1511 * In the code above the something_send_fn() function of the next
1512 * module in the stack will be called as root.
1513 * The smb_vfs_call_something_*() glue code, which is the magic
1514 * behind the SMB_VFS_SOMETHING[_NEXT]_{SEND,RECV}() macros,
1515 * will look like this:
1517 * struct smb_vfs_call_something_state {
1518 * ssize_t (*recv_fn)(struct tevent_req *req,
1519 * struct vfs_aio_state *aio_state,
1522 * struct vfs_aio_state vfs_aio_state;
1526 * static void smb_vfs_call_something_done(struct tevent_req *subreq);
1528 * struct tevent_req *smb_vfs_call_something_send(
1529 * TALLOC_CTX *mem_ctx,
1530 * const struct smb_vfs_ev_glue *evg,
1531 * struct vfs_handle_struct *handle,
1534 * struct tevent_req *req = NULL;
1535 * struct smb_vfs_call_something_state *state = NULL;
1536 * struct tevent_req *subreq = NULL;
1539 * req = tevent_req_create(mem_ctx, &state,
1540 * struct smb_vfs_call_something_state);
1541 * if (req == NULL) {
1545 * VFS_FIND(something_send);
1546 * state->recv_fn = handle->fns->something_recv_fn;
1548 * ok = smb_vfs_ev_glue_push_use(evg, req);
1550 * tevent_req_error(req, EIO);
1551 * return tevent_req_post(req, evg->return_ev);
1554 * subreq = handle->fns->something_send_fn(mem_ctx,
1558 * smb_vfs_ev_glue_pop_use(evg);
1560 * if (tevent_req_nomem(subreq, req)) {
1561 * return tevent_req_post(req, evg->return_ev);
1563 * tevent_req_set_callback(subreq, smb_vfs_call_something_done, req);
1568 * static void smb_vfs_call_something_done(struct tevent_req *subreq)
1570 * struct tevent_req *req =
1571 * tevent_req_callback_data(subreq,
1572 * struct tevent_req);
1573 * struct smb_vfs_call_something_state *state =
1574 * tevent_req_data(req,
1575 * struct smb_vfs_call_something_state);
1577 * state->retval = state->recv_fn(subreq,
1578 * &state->vfs_aio_state,
1580 * TALLOC_FREE(subreq);
1582 * if (state->retval == -1) {
1583 * tevent_req_error(req, state->vfs_aio_state.error);
1586 * tevent_req_done(req);
1589 * ssize_t smb_vfs_call_something_recv(struct tevent_req *req,
1590 * struct vfs_aio_state *aio_state,
1593 * struct smb_vfs_call_something_state *state =
1594 * tevent_req_data(req,
1595 * struct smb_vfs_call_something_state);
1596 * ssize_t retval = state->retval;
1598 * if (tevent_req_is_unix_error(req, &aio_state->error)) {
1599 * tevent_req_received(req);
1603 * *aio_state = state->vfs_aio_state;
1606 * tevent_req_received(req);
1610 * The most important details are these:
1612 * 1. smb_vfs_ev_glue_push_use(evg, req):
1613 * - is a no-op if evg->run_ev and evg->return_ev are the same,
1614 * it means that we're already at the correct impersonation
1615 * and don't need any additional work to be done.
1616 * - Otherwise it will call tevent_req_defer_callback(req, evg->return_ev)
1617 * This means that tevent_req_error() and tevent_req_done()
1618 * will just trigger an immediate event on evg->return_ev.
1619 * Therefore the callers callback function will be called
1620 * in the impersonation of evg->return_ev! This is important
1621 * in order to get the impersonation correct on the way back
1622 * through the stack.
1623 * - It will call tevent_context_push_use(evg->run_ev),
1624 * which will start the impersonation to run_ev.
1625 * So the following code run in the correct context.
1626 * 2. handle->fns->something_send_fn(..., evg->next_glue, ...):
1627 * - We're passing evg->next_glue to the next module.
1628 * - Typically evg->next_glue points to evg again.
1629 * - In case evg->run_ev and evg->return_ev are not the same,
1630 * next_glue will have run_ev and return_ev pointing to evg->run_ev.
1631 * So that the switch from evg->run_ev to evg->return_ev
1632 * happens on the correct boundary.
1633 * 3. smb_vfs_ev_glue_pop_use(evg):
1634 * - is a no-op if evg->run_ev and evg->return_ev are the same,
1635 * it means that we're already at the correct impersonation
1636 * and don't need any additional work to be done.
1637 * - It will call tevent_context_pop_use(evg->run_ev),
1638 * which will revert the impersonation done in
1639 * smb_vfs_ev_glue_push_use().
1640 * 4. smb_vfs_call_something_send():
1641 * - The is called in the environment of evg->return_ev.
1642 * - So it needs to use tevent_req_post(req, evg->return_ev)
1643 * 5. smb_vfs_call_something_done():
1644 * - The is called in the environment of evg->run_ev
1645 * 6. smb_vfs_call_something_recv():
1646 * - The is called in the environment of evg->return_ev again.
1649 * Here are some more complex examples:
1651 * Example 1: only user_evg without switch to root
1653 * SMBD: already impersonated user_evg
1654 * evg'1 = smb2_req->user_evg
1655 * r'1 = SMB_VFS_*_SEND(evg'1); # smb_vfs_call_*_send()
1657 * | smb_vfs_ev_glue_push_use(evg'1, r'1);
1659 * | | # no-op run_ev == return_ev
1661 * | evg'2 = evg'1->next_glue;
1662 * | r'2 = module1_*_send(evg'2);
1665 * | | r'3 = SMB_VFS_*_NEXT_SEND(evg'3); # smb_vfs_call_*_send()
1667 * | | | smb_vfs_ev_glue_push_use(evg'3, r'3);
1669 * | | | | # no-op run_ev == return_ev
1671 * | | | evg'4 = evg'3->next_glue;
1672 * | | | r'4 = module2_*_send(evg'4);
1674 * | | | | evg'5 = evg'4
1675 * | | | | r'5 = SMB_VFS_*_NEXT_SEND(evg'5); # smb_vfs_call_*_send()
1677 * | | | | | smb_vfs_ev_glue_push_use(evg'5, r'5);
1679 * | | | | | | # no-op run_ev == return_ev
1681 * | | | | | evg'6 = evg'5->next_glue;
1682 * | | | | | r'6 = default_*_send(evg'6);
1684 * | | | | | | ev'6 = smb_vfs_ev_glue_ev_ctx(evg'6)
1685 * | | | | | | tp'6 = smb_vfs_ev_glue_tp_chdir_safe(evg'6)
1686 * | | | | | | r'7 = pthreadpool_tevent_send(ev'6, tp'6);
1688 * | | | | | | | pthread_create...
1690 * | | | | | | tevent_req_set_callback(r'7, default_*_done, r'6);
1692 * | | | | | smb_vfs_ev_glue_pop_use(evg'5);
1694 * | | | | | | # no-op run_ev == return_ev
1696 * | | | | | tevent_req_set_callback(r'6, smb_vfs_call_*_done, r'5);
1698 * | | | | tevent_req_set_callback(r'5, module2_*_done, r'4);
1700 * | | | smb_vfs_ev_glue_pop_use(evg'3);
1702 * | | | | # no-op run_ev == return_ev
1704 * | | | tevent_req_set_callback(r'4, smb_vfs_call_*_done, r'3);
1706 * | | tevent_req_set_callback(r'3, module1_*_done, r'2);
1708 * | smb_vfs_ev_glue_pop_use(evg'1);
1710 * | | # no-op run_ev == return_ev
1712 * | tevent_req_set_callback(r'2, smb_vfs_call_*_done, r'1);
1714 * tevent_req_set_callback(r'1, smbd_*_done, smb2_req);
1716 * Worker thread finished, just one event handler processes
1717 * everything as there's no impersonation change.
1719 * tevent_common_invoke_immediate_handler:
1721 * | before_immediate_handler(ev'6);
1723 * | | change_to_user()
1725 * | pthreadpool_tevent_job_done(r'7);
1727 * | | default_*_done(r'7);
1729 * | | | pthreadpool_tevent_recv(r'7);
1730 * | | | TALLOC_FREE(r'7);
1731 * | | | tevent_req_done('r6);
1733 * | | | | smb_vfs_call_*_done(r'6);
1735 * | | | | | default_*_recv(r'6);
1736 * | | | | | TALLOC_FREE(r'6)
1737 * | | | | | tevent_req_done(r'5);
1739 * | | | | | | module2_*_done(r'5):
1741 * | | | | | | | SMB_VFS_*_recv(r'5); # smb_vfs_call_*_recv()
1742 * | | | | | | | TALLOC_FREE(r'5)
1743 * | | | | | | | tevent_req_done(r'4);
1745 * | | | | | | | | smb_vfs_call_*_done(r'4);
1747 * | | | | | | | | | module2_*_recv(r'4);
1748 * | | | | | | | | | TALLOC_FREE(r'4)
1749 * | | | | | | | | | tevent_req_done(r'3);
1750 * | | | | | | | | | |
1751 * | | | | | | | | | | module1_*_done(r'3):
1752 * | | | | | | | | | | |
1753 * | | | | | | | | | | | SMB_VFS_*_recv(r'3); # smb_vfs_call_*_recv()
1754 * | | | | | | | | | | | TALLOC_FREE(r'3)
1755 * | | | | | | | | | | | tevent_req_done(r'2);
1756 * | | | | | | | | | | | |
1757 * | | | | | | | | | | | | smb_vfs_*_done(r'2);
1758 * | | | | | | | | | | | | |
1759 * | | | | | | | | | | | | | module1_*_recv(r'2);
1760 * | | | | | | | | | | | | | TALLOC_FREE(r'2)
1761 * | | | | | | | | | | | | | tevent_req_done(r'1);
1762 * | | | | | | | | | | | | | |
1763 * | | | | | | | | | | | | | | smbd_*_done(r'1);
1764 * | | | | | | | | | | | | | | |
1765 * | | | | | | | | | | | | | | | SMB_VFS_*_recv(r'1); # smb_vfs_call_*_recv()
1766 * | | | | | | | | | | | | | | | TALLOC_FREE(r'1)
1767 * | | | | | | | | | | | | | | | smbd_response_to_client()
1768 * | | | | | | | | | | | | | | | return
1769 * | | | | | | | | | | | | | | |
1770 * | | | | | | | | | | | | | | return
1771 * | | | | | | | | | | | | | |
1772 * | | | | | | | | | | | | | return
1773 * | | | | | | | | | | | | |
1774 * | | | | | | | | | | | | return
1775 * | | | | | | | | | | | |
1776 * | | | | | | | | | | | return
1777 * | | | | | | | | | | |
1778 * | | | | | | | | | | return
1779 * | | | | | | | | | |
1780 * | | | | | | | | | return
1782 * | | | | | | | | return
1784 * | | | | | | | return
1786 * | | | | | | return
1796 * | after_immediate_handler(ev'6);
1798 * | | # lazy no change_to_user()
1803 * Example 2: start with user_evg and let module1 switch to root
1805 * SMBD: already impersonated user_evg
1806 * evg'1 = smb2_req->user_evg
1807 * r'1 = SMB_VFS_*_SEND(evg'1); # smb_vfs_call_*_send()
1809 * | smb_vfs_ev_glue_push_use(evg'1, r'1);
1811 * | | # no-op run_ev == return_ev
1813 * | evg'2 = evg'1->next_glue;
1814 * | r'2 = module1_*_send(evg'2);
1816 * | | evg'3 = smb_vfs_ev_glue_get_root_glue(evg'2)
1817 * | | r'3 = SMB_VFS_*_NEXT_SEND(evg'3); # smb_vfs_call_*_send()
1819 * | | | smb_vfs_ev_glue_push_use(evg'3, r'3);
1821 * | | | | tevent_req_defer_callback(r'3, evg'3->return_ev);
1822 * | | | | tevent_context_push_use(evg'3->run_ev)
1824 * | | | | | become_root()
1827 * | | | evg'4 = evg'3->next_glue;
1828 * | | | r'4 = module2_*_send(evg'4);
1830 * | | | | evg'5 = smb_vfs_ev_glue_get_root_glue(evg'4)
1831 * | | | | r'5 = SMB_VFS_*_NEXT_SEND(evg'5); # smb_vfs_call_*_send()
1833 * | | | | | smb_vfs_ev_glue_push_use(evg'5, r'5);
1835 * | | | | | | # no-op run_ev == return_ev, already root
1837 * | | | | | evg'6 = evg'5->next_glue;
1838 * | | | | | r'6 = default_*_send(evg'6);
1840 * | | | | | | ev'6 = smb_vfs_ev_glue_ev_ctx(evg'6)
1841 * | | | | | | tp'6 = smb_vfs_ev_glue_tp_chdir_safe(evg'6)
1842 * | | | | | | r'7 = pthreadpool_tevent_send(ev'6, tp'6);
1844 * | | | | | | | pthread_create...
1846 * | | | | | | tevent_req_set_callback(r'7, default_*_done, r'6);
1848 * | | | | | smb_vfs_ev_glue_pop_use(evg'5);
1850 * | | | | | | # no-op run_ev == return_ev, still stay as root
1852 * | | | | | tevent_req_set_callback(r'6, smb_vfs_*_done, r'5);
1854 * | | | | tevent_req_set_callback(r'5, module2_*_done, r'4);
1856 * | | | smb_vfs_ev_glue_pop_use(evg'3);
1858 * | | | | tevent_context_pop_use(evg'3->run_ev)
1860 * | | | | | unbecome_root()
1862 * | | | tevent_req_set_callback(r'4, smb_vfs_*_done, r'3);
1864 * | | tevent_req_set_callback(r'3, module1_*_done, r'2);
1866 * | smb_vfs_ev_glue_pop_use(evg'1);
1868 * | | # no-op run_ev == return_ev
1870 * | tevent_req_set_callback(r'2, smb_vfs_*_done, r'1);
1872 * tevent_req_set_callback(r'1, smbd_*_done, smb2_req);
1874 * Worker thread finished, just one event handler processes
1875 * everything as there's no impersonation change.
1877 * tevent_common_invoke_immediate_handler:
1879 * | before_immediate_handler(ev'6);
1883 * | pthreadpool_tevent_job_done(r'7);
1885 * | | default_*_done(r'7);
1887 * | | | pthreadpool_tevent_recv(r'7);
1888 * | | | TALLOC_FREE(r'7);
1889 * | | | tevent_req_done('r6);
1891 * | | | | smb_vfs_*_done(r'6);
1893 * | | | | | default_*_recv(r'6);
1894 * | | | | | TALLOC_FREE(r'6)
1895 * | | | | | tevent_req_done(r'5);
1897 * | | | | | | module2_*_done(r'5):
1899 * | | | | | | | SMB_VFS_*_recv(r'5);
1900 * | | | | | | | TALLOC_FREE(r'5)
1901 * | | | | | | | tevent_req_done(r'4);
1903 * | | | | | | | | smb_vfs_*_done(r'4);
1905 * | | | | | | | | | module2_*_recv(r'4);
1906 * | | | | | | | | | TALLOC_FREE(r'4)
1907 * | | | | | | | | | tevent_req_done(r'3);
1908 * | | | | | | | | | | return
1909 * | | | | | | | | | |
1910 * | | | | | | | | | return
1912 * | | | | | | | | return
1914 * | | | | | | | return
1916 * | | | | | | return
1927 * | after_immediate_handler(ev'6);
1929 * | | unbecome_root()
1933 * tevent_common_invoke_immediate_handler:
1935 * | before_immediate_handler(ev'6);
1937 * | | change_to_user()
1939 * | tevent_req_trigger();
1941 * | _tevent_req_notify_callback(r'3)
1943 * | | module1_*_done(r'3):
1945 * | | | SMB_VFS_*_recv(r'3);
1946 * | | | TALLOC_FREE(r'3)
1947 * | | | tevent_req_done(r'2);
1949 * | | | | smb_vfs_*_done(r'2);
1951 * | | | | | module1_*_recv(r'2);
1952 * | | | | | TALLOC_FREE(r'2)
1953 * | | | | | tevent_req_done(r'1);
1955 * | | | | | | smbd_*_done(r'1);
1957 * | | | | | | | SMB_VFS_*_recv(r'1);
1958 * | | | | | | | TALLOC_FREE(r'1)
1959 * | | | | | | | smbd_response_to_client()
1960 * | | | | | | | return
1962 * | | | | | | return
1972 * | after_immediate_handler(ev'6);
1974 * | | # lazy no change_to_user()
1979 struct smb_vfs_ev_glue {
1981 * The event context that should be used
1982 * to report the result back.
1984 * The is basically the callers context.
1986 struct tevent_context *return_ev;
1989 * The event context and threadpool wrappers
1990 * the current context should use.
1992 * tp_fd_safe only allows fd based functions
1993 * which don't require impersonation, this
1994 * is basically the raw threadpool.
1996 * tp_path_safe allows path based functions
1997 * to be called under the correct impersonation.
1998 * But chdir/fchdir is not allowed!
1999 * Typically calls like openat() or other *at()
2002 * tp_chdir_safe is like path_safe, but also
2003 * allows chdir/fchdir to be called, the job
2004 * can safely return with a changed directory,
2005 * the threadpool wrapper takes care of
2006 * a cleanup if required.
2007 * This is needed if *at() syscalls need
2008 * to be simulated by fchdir();$syscall(),
2011 * The distinction between these threadpool
2012 * is required because of OS limitations
2014 * - only Linux supports per thread
2015 * credentials (seteuid....)
2016 * - only Linux supports a per thread
2017 * current working directory,
2018 * using unshare(CLONE_FS). But
2019 * in some constrained container
2020 * environments even that is not available
2023 * tp_fd_safe is typically the raw threadpool
2024 * without a wrapper.
2026 * On Linux tp_path_safe and tp_chdir_safe
2027 * are typically the same (if unshare(CLONE_FS) is available)
2028 * they're implemented as wrappers of the raw threadpool.
2030 * On other OSes tp_path_safe is a wrapper
2031 * arround a sync threadpool (without real threads, just blocking
2032 * the main thread), but hidden behind the pthreadpool_tevent
2033 * api in order to make the restriction transparent.
2035 * On other OSes tp_chdir_safe is a wrapper
2036 * arround a sync threadpool (without real threads, just blocking
2037 * the main thread), but hidden behind the pthreadpool_tevent
2038 * api in order to make the restriction transparent.
2039 * It just remembers/restores the current working directory,
2040 * typically using open(".", O_RDONLY | O_DIRECTORY) and fchdir().
2042 struct tevent_context *run_ev;
2043 struct pthreadpool_tevent *run_tp_fd_safe;
2044 struct pthreadpool_tevent *run_tp_path_safe;
2045 struct pthreadpool_tevent *run_tp_chdir_safe;
2048 * The glue that should be passed down
2049 * to sub request in the stack.
2051 * Typically this points to itself.
2053 * But smb_vfs_ev_glue_create_switch() allows
2054 * to create context that can switch
2055 * between two user glues.
2057 const struct smb_vfs_ev_glue *next_glue;
2060 * If some code path wants to run
2061 * some constraint code as root,
2062 * basically an async version of become_root()
2063 * and unbecome_root().
2065 * The caller can call smb_vfs_ev_glue_get_root_glue()
2066 * to get a root glue that can be passed
2067 * to the SMB_VFS_*_SEND() function that
2068 * should run as root.
2070 * Note that the callback (registered with
2071 * tevent_req_set_callback()) won't run as
2074 const struct smb_vfs_ev_glue *root_glue;
2077 static struct smb_vfs_ev_glue *smb_vfs_ev_glue_create_internal(
2078 TALLOC_CTX *mem_ctx,
2079 struct tevent_context *return_ev,
2080 struct tevent_context *run_ev,
2081 struct pthreadpool_tevent *run_tp_fd_safe,
2082 struct pthreadpool_tevent *run_tp_path_safe,
2083 struct pthreadpool_tevent *run_tp_chdir_safe)
2085 struct smb_vfs_ev_glue *evg = NULL;
2087 evg = talloc_zero(mem_ctx, struct smb_vfs_ev_glue);
2091 *evg = (struct smb_vfs_ev_glue) {
2092 .return_ev = return_ev,
2094 .run_tp_fd_safe = run_tp_fd_safe,
2095 .run_tp_path_safe = run_tp_path_safe,
2096 .run_tp_chdir_safe = run_tp_chdir_safe,
2103 struct tevent_context *smb_vfs_ev_glue_ev_ctx(const struct smb_vfs_ev_glue *evg)
2108 struct pthreadpool_tevent *smb_vfs_ev_glue_tp_fd_safe(const struct smb_vfs_ev_glue *evg)
2110 return evg->run_tp_fd_safe;
2113 struct pthreadpool_tevent *smb_vfs_ev_glue_tp_path_safe(const struct smb_vfs_ev_glue *evg)
2115 return evg->run_tp_path_safe;
2118 struct pthreadpool_tevent *smb_vfs_ev_glue_tp_chdir_safe(const struct smb_vfs_ev_glue *evg)
2120 return evg->run_tp_chdir_safe;
2123 const struct smb_vfs_ev_glue *smb_vfs_ev_glue_get_root_glue(const struct smb_vfs_ev_glue *evg)
2125 return evg->root_glue;
2128 struct smb_vfs_ev_glue *smb_vfs_ev_glue_create(TALLOC_CTX *mem_ctx,
2129 struct tevent_context *user_ev,
2130 struct pthreadpool_tevent *user_tp_fd_safe,
2131 struct pthreadpool_tevent *user_tp_path_safe,
2132 struct pthreadpool_tevent *user_tp_chdir_safe,
2133 struct tevent_context *root_ev,
2134 struct pthreadpool_tevent *root_tp_fd_safe,
2135 struct pthreadpool_tevent *root_tp_path_safe,
2136 struct pthreadpool_tevent *root_tp_chdir_safe)
2138 struct smb_vfs_ev_glue *evg_uu = NULL;
2139 struct smb_vfs_ev_glue *evg_ru = NULL;
2140 struct smb_vfs_ev_glue *evg_rr = NULL;
2143 * The top level glue (directly returned from this function).
2145 * It uses user_ev and user_tp_* only.
2147 evg_uu = smb_vfs_ev_glue_create_internal(mem_ctx,
2148 user_ev, /* return_ev */
2149 user_ev, /* run_ev */
2152 user_tp_chdir_safe);
2153 if (evg_uu == NULL) {
2158 * The first root glue (returned by smb_vfs_ev_glue_get_root_glue()).
2160 * It uses root_ev and root_tp, but user_ev as return ev,
2161 * which means that the caller's callback (registered with
2162 * tevent_req_set_callback()) will run as user_ev.
2164 evg_ru = smb_vfs_ev_glue_create_internal(evg_uu,
2165 user_ev, /* return_ev */
2166 root_ev, /* run_ev */
2169 root_tp_chdir_safe);
2170 if (evg_ru == NULL) {
2171 TALLOC_FREE(evg_uu);
2176 * The second root glue (returned by smb_vfs_ev_glue_get_root_glue() on
2177 * root glue itself. This means code can always call
2178 * smb_vfs_ev_glue_get_root_glue() and don't have to care if the
2179 * passed glue is already a root glue.
2181 * This will then recursively point to its own root_glue pointer.
2183 * It only uses root_ev and root_tp.
2185 evg_rr = smb_vfs_ev_glue_create_internal(evg_ru,
2186 root_ev, /* return_ev */
2187 root_ev, /* run_ev */
2190 root_tp_chdir_safe);
2191 if (evg_rr == NULL) {
2192 TALLOC_FREE(evg_uu);
2197 * We now setup the glue hierarchy.
2199 * Search for "Design of the smb_vfs_ev_glue infrastructure" above
2200 * for a detailed description how the chain works.
2202 * "Example 2: start with user_evg and let module1 switch to root"
2203 * explains it for the root_glue chaining.
2205 evg_rr->root_glue = evg_rr;
2206 evg_ru->root_glue = evg_rr;
2207 evg_uu->root_glue = evg_ru;
2210 * As evg_ru is a boundary with
2211 * run_ev != return_ev, we need to
2212 * alter its next_glue.
2214 evg_ru->next_glue = evg_rr;
2220 * This can be used to create a temporary glue
2221 * if you need to switch between two user contexts
2223 * It's the caller's duty to make sure both
2224 * glues stay alive for the lifetime of the
2227 struct smb_vfs_ev_glue *smb_vfs_ev_glue_create_switch(
2228 TALLOC_CTX *mem_ctx,
2229 const struct smb_vfs_ev_glue *return_evg,
2230 const struct smb_vfs_ev_glue *run_evg)
2232 const struct smb_vfs_ev_glue *run_root = run_evg->root_glue;
2233 struct smb_vfs_ev_glue *evg_u = NULL;
2234 struct smb_vfs_ev_glue *evg_r = NULL;
2237 * Here we basically need to dup run_evg (and run_evg->root_glue)
2238 * and replace their return_ev with return_evg->return_ev.
2240 * We need to put the new evgs in front of the chain...
2242 evg_u = smb_vfs_ev_glue_create_internal(mem_ctx,
2243 return_evg->return_ev,
2245 run_evg->run_tp_fd_safe,
2246 run_evg->run_tp_path_safe,
2247 run_evg->run_tp_chdir_safe);
2248 if (evg_u == NULL) {
2252 evg_r = smb_vfs_ev_glue_create_internal(evg_u,
2253 return_evg->return_ev,
2255 run_root->run_tp_fd_safe,
2256 run_root->run_tp_path_safe,
2257 run_root->run_tp_chdir_safe);
2258 if (evg_r == NULL) {
2263 * evg_r is a boundary with run_ev != return_ev.
2264 * As run_root is also a boundary, we need to
2265 * use run_root->next_glue in order to get
2266 * a glue that stays as root.
2268 * The same applies to the chaining of root
2271 evg_r->next_glue = run_root->next_glue;
2272 evg_r->root_glue = run_root->root_glue;
2275 * evg_r is a boundary with run_ev != return_ev.
2276 * But run_evg is typically not a boundary,
2277 * we use it directly as next_glue.
2279 * And the root_glue is the one we constructed above.
2281 evg_u->next_glue = run_evg;
2282 evg_u->root_glue = evg_r;
2287 static bool smb_vfs_ev_glue_push_use(const struct smb_vfs_ev_glue *evg,
2288 struct tevent_req *req)
2290 if (evg->run_ev == evg->return_ev) {
2292 * We're already in the correct
2293 * impersonation environment.
2299 * Make sure that our callers callback function
2300 * will be called in the return_ev environment.
2302 tevent_req_defer_callback(req, evg->return_ev);
2305 * let the event context wrapper do
2306 * the required impersonation.
2308 return tevent_context_push_use(evg->run_ev);
2311 static void smb_vfs_ev_glue_pop_use(const struct smb_vfs_ev_glue *evg)
2313 if (evg->run_ev == evg->return_ev) {
2315 * smb_vfs_ev_glue_push_use() didn't
2316 * change the impersonation environment.
2322 * undo the impersonation
2324 tevent_context_pop_use(evg->run_ev);
2327 int smb_vfs_call_connect(struct vfs_handle_struct *handle,
2328 const char *service, const char *user)
2331 return handle->fns->connect_fn(handle, service, user);
2334 void smb_vfs_call_disconnect(struct vfs_handle_struct *handle)
2336 VFS_FIND(disconnect);
2337 handle->fns->disconnect_fn(handle);
2340 uint64_t smb_vfs_call_disk_free(struct vfs_handle_struct *handle,
2341 const struct smb_filename *smb_fname,
2346 VFS_FIND(disk_free);
2347 return handle->fns->disk_free_fn(handle, smb_fname,
2348 bsize, dfree, dsize);
2351 int smb_vfs_call_get_quota(struct vfs_handle_struct *handle,
2352 const struct smb_filename *smb_fname,
2353 enum SMB_QUOTA_TYPE qtype,
2357 VFS_FIND(get_quota);
2358 return handle->fns->get_quota_fn(handle, smb_fname, qtype, id, qt);
2361 int smb_vfs_call_set_quota(struct vfs_handle_struct *handle,
2362 enum SMB_QUOTA_TYPE qtype, unid_t id,
2365 VFS_FIND(set_quota);
2366 return handle->fns->set_quota_fn(handle, qtype, id, qt);
2369 int smb_vfs_call_get_shadow_copy_data(struct vfs_handle_struct *handle,
2370 struct files_struct *fsp,
2371 struct shadow_copy_data *shadow_copy_data,
2374 VFS_FIND(get_shadow_copy_data);
2375 return handle->fns->get_shadow_copy_data_fn(handle, fsp,
2379 int smb_vfs_call_statvfs(struct vfs_handle_struct *handle,
2380 const struct smb_filename *smb_fname,
2381 struct vfs_statvfs_struct *statbuf)
2384 return handle->fns->statvfs_fn(handle, smb_fname, statbuf);
2387 uint32_t smb_vfs_call_fs_capabilities(struct vfs_handle_struct *handle,
2388 enum timestamp_set_resolution *p_ts_res)
2390 VFS_FIND(fs_capabilities);
2391 return handle->fns->fs_capabilities_fn(handle, p_ts_res);
2394 NTSTATUS smb_vfs_call_get_dfs_referrals(struct vfs_handle_struct *handle,
2395 struct dfs_GetDFSReferral *r)
2397 VFS_FIND(get_dfs_referrals);
2398 return handle->fns->get_dfs_referrals_fn(handle, r);
2401 DIR *smb_vfs_call_opendir(struct vfs_handle_struct *handle,
2402 const struct smb_filename *smb_fname,
2404 uint32_t attributes)
2407 return handle->fns->opendir_fn(handle, smb_fname, mask, attributes);
2410 DIR *smb_vfs_call_fdopendir(struct vfs_handle_struct *handle,
2411 struct files_struct *fsp,
2413 uint32_t attributes)
2415 VFS_FIND(fdopendir);
2416 return handle->fns->fdopendir_fn(handle, fsp, mask, attributes);
2419 struct dirent *smb_vfs_call_readdir(struct vfs_handle_struct *handle,
2421 SMB_STRUCT_STAT *sbuf)
2424 return handle->fns->readdir_fn(handle, dirp, sbuf);
2427 void smb_vfs_call_seekdir(struct vfs_handle_struct *handle,
2428 DIR *dirp, long offset)
2431 handle->fns->seekdir_fn(handle, dirp, offset);
2434 long smb_vfs_call_telldir(struct vfs_handle_struct *handle,
2438 return handle->fns->telldir_fn(handle, dirp);
2441 void smb_vfs_call_rewind_dir(struct vfs_handle_struct *handle,
2444 VFS_FIND(rewind_dir);
2445 handle->fns->rewind_dir_fn(handle, dirp);
2448 int smb_vfs_call_mkdir(struct vfs_handle_struct *handle,
2449 const struct smb_filename *smb_fname,
2453 return handle->fns->mkdir_fn(handle, smb_fname, mode);
2456 int smb_vfs_call_rmdir(struct vfs_handle_struct *handle,
2457 const struct smb_filename *smb_fname)
2460 return handle->fns->rmdir_fn(handle, smb_fname);
2463 int smb_vfs_call_closedir(struct vfs_handle_struct *handle,
2467 return handle->fns->closedir_fn(handle, dir);
2470 int smb_vfs_call_open(struct vfs_handle_struct *handle,
2471 struct smb_filename *smb_fname, struct files_struct *fsp,
2472 int flags, mode_t mode)
2475 return handle->fns->open_fn(handle, smb_fname, fsp, flags, mode);
2478 NTSTATUS smb_vfs_call_create_file(struct vfs_handle_struct *handle,
2479 struct smb_request *req,
2480 uint16_t root_dir_fid,
2481 struct smb_filename *smb_fname,
2482 uint32_t access_mask,
2483 uint32_t share_access,
2484 uint32_t create_disposition,
2485 uint32_t create_options,
2486 uint32_t file_attributes,
2487 uint32_t oplock_request,
2488 struct smb2_lease *lease,
2489 uint64_t allocation_size,
2490 uint32_t private_flags,
2491 struct security_descriptor *sd,
2492 struct ea_list *ea_list,
2493 files_struct **result,
2495 const struct smb2_create_blobs *in_context_blobs,
2496 struct smb2_create_blobs *out_context_blobs)
2498 VFS_FIND(create_file);
2499 return handle->fns->create_file_fn(
2500 handle, req, root_dir_fid, smb_fname, access_mask,
2501 share_access, create_disposition, create_options,
2502 file_attributes, oplock_request, lease, allocation_size,
2503 private_flags, sd, ea_list,
2504 result, pinfo, in_context_blobs, out_context_blobs);
2507 int smb_vfs_call_close(struct vfs_handle_struct *handle,
2508 struct files_struct *fsp)
2511 return handle->fns->close_fn(handle, fsp);
2514 ssize_t smb_vfs_call_pread(struct vfs_handle_struct *handle,
2515 struct files_struct *fsp, void *data, size_t n,
2519 return handle->fns->pread_fn(handle, fsp, data, n, offset);
2522 struct smb_vfs_call_pread_state {
2523 ssize_t (*recv_fn)(struct tevent_req *req, struct vfs_aio_state *vfs_aio_state);
2525 struct vfs_aio_state vfs_aio_state;
2528 static void smb_vfs_call_pread_done(struct tevent_req *subreq);
2530 struct tevent_req *smb_vfs_call_pread_send(struct vfs_handle_struct *handle,
2531 TALLOC_CTX *mem_ctx,
2532 struct tevent_context *ev,
2533 struct files_struct *fsp,
2535 size_t n, off_t offset)
2537 struct tevent_req *req, *subreq;
2538 struct smb_vfs_call_pread_state *state;
2540 req = tevent_req_create(mem_ctx, &state,
2541 struct smb_vfs_call_pread_state);
2545 VFS_FIND(pread_send);
2546 state->recv_fn = handle->fns->pread_recv_fn;
2548 subreq = handle->fns->pread_send_fn(handle, state, ev, fsp, data, n,
2550 if (tevent_req_nomem(subreq, req)) {
2551 return tevent_req_post(req, ev);
2553 tevent_req_set_callback(subreq, smb_vfs_call_pread_done, req);
2557 static void smb_vfs_call_pread_done(struct tevent_req *subreq)
2559 struct tevent_req *req = tevent_req_callback_data(
2560 subreq, struct tevent_req);
2561 struct smb_vfs_call_pread_state *state = tevent_req_data(
2562 req, struct smb_vfs_call_pread_state);
2564 state->retval = state->recv_fn(subreq, &state->vfs_aio_state);
2565 TALLOC_FREE(subreq);
2566 if (state->retval == -1) {
2567 tevent_req_error(req, state->vfs_aio_state.error);
2570 tevent_req_done(req);
2573 ssize_t SMB_VFS_PREAD_RECV(struct tevent_req *req,
2574 struct vfs_aio_state *vfs_aio_state)
2576 struct smb_vfs_call_pread_state *state = tevent_req_data(
2577 req, struct smb_vfs_call_pread_state);
2580 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
2581 tevent_req_received(req);
2584 *vfs_aio_state = state->vfs_aio_state;
2585 retval = state->retval;
2586 tevent_req_received(req);
2590 ssize_t smb_vfs_call_pwrite(struct vfs_handle_struct *handle,
2591 struct files_struct *fsp, const void *data,
2592 size_t n, off_t offset)
2595 return handle->fns->pwrite_fn(handle, fsp, data, n, offset);
2598 struct smb_vfs_call_pwrite_state {
2599 ssize_t (*recv_fn)(struct tevent_req *req, struct vfs_aio_state *vfs_aio_state);
2601 struct vfs_aio_state vfs_aio_state;
2604 static void smb_vfs_call_pwrite_done(struct tevent_req *subreq);
2606 struct tevent_req *smb_vfs_call_pwrite_send(struct vfs_handle_struct *handle,
2607 TALLOC_CTX *mem_ctx,
2608 struct tevent_context *ev,
2609 struct files_struct *fsp,
2611 size_t n, off_t offset)
2613 struct tevent_req *req, *subreq;
2614 struct smb_vfs_call_pwrite_state *state;
2616 req = tevent_req_create(mem_ctx, &state,
2617 struct smb_vfs_call_pwrite_state);
2621 VFS_FIND(pwrite_send);
2622 state->recv_fn = handle->fns->pwrite_recv_fn;
2624 subreq = handle->fns->pwrite_send_fn(handle, state, ev, fsp, data, n,
2626 if (tevent_req_nomem(subreq, req)) {
2627 return tevent_req_post(req, ev);
2629 tevent_req_set_callback(subreq, smb_vfs_call_pwrite_done, req);
2633 static void smb_vfs_call_pwrite_done(struct tevent_req *subreq)
2635 struct tevent_req *req = tevent_req_callback_data(
2636 subreq, struct tevent_req);
2637 struct smb_vfs_call_pwrite_state *state = tevent_req_data(
2638 req, struct smb_vfs_call_pwrite_state);
2640 state->retval = state->recv_fn(subreq, &state->vfs_aio_state);
2641 TALLOC_FREE(subreq);
2642 if (state->retval == -1) {
2643 tevent_req_error(req, state->vfs_aio_state.error);
2646 tevent_req_done(req);
2649 ssize_t SMB_VFS_PWRITE_RECV(struct tevent_req *req,
2650 struct vfs_aio_state *vfs_aio_state)
2652 struct smb_vfs_call_pwrite_state *state = tevent_req_data(
2653 req, struct smb_vfs_call_pwrite_state);
2656 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
2657 tevent_req_received(req);
2660 *vfs_aio_state = state->vfs_aio_state;
2661 retval = state->retval;
2662 tevent_req_received(req);
2666 off_t smb_vfs_call_lseek(struct vfs_handle_struct *handle,
2667 struct files_struct *fsp, off_t offset,
2671 return handle->fns->lseek_fn(handle, fsp, offset, whence);
2674 ssize_t smb_vfs_call_sendfile(struct vfs_handle_struct *handle, int tofd,
2675 files_struct *fromfsp, const DATA_BLOB *header,
2676 off_t offset, size_t count)
2679 return handle->fns->sendfile_fn(handle, tofd, fromfsp, header, offset,
2683 ssize_t smb_vfs_call_recvfile(struct vfs_handle_struct *handle, int fromfd,
2684 files_struct *tofsp, off_t offset,
2688 return handle->fns->recvfile_fn(handle, fromfd, tofsp, offset, count);
2691 int smb_vfs_call_rename(struct vfs_handle_struct *handle,
2692 const struct smb_filename *smb_fname_src,
2693 const struct smb_filename *smb_fname_dst)
2696 return handle->fns->rename_fn(handle, smb_fname_src, smb_fname_dst);
2699 struct smb_vfs_call_fsync_state {
2700 int (*recv_fn)(struct tevent_req *req, struct vfs_aio_state *vfs_aio_state);
2702 struct vfs_aio_state vfs_aio_state;
2705 static void smb_vfs_call_fsync_done(struct tevent_req *subreq);
2707 struct tevent_req *smb_vfs_call_fsync_send(struct vfs_handle_struct *handle,
2708 TALLOC_CTX *mem_ctx,
2709 struct tevent_context *ev,
2710 struct files_struct *fsp)
2712 struct tevent_req *req, *subreq;
2713 struct smb_vfs_call_fsync_state *state;
2715 req = tevent_req_create(mem_ctx, &state,
2716 struct smb_vfs_call_fsync_state);
2720 VFS_FIND(fsync_send);
2721 state->recv_fn = handle->fns->fsync_recv_fn;
2723 subreq = handle->fns->fsync_send_fn(handle, state, ev, fsp);
2724 if (tevent_req_nomem(subreq, req)) {
2725 return tevent_req_post(req, ev);
2727 tevent_req_set_callback(subreq, smb_vfs_call_fsync_done, req);
2731 static void smb_vfs_call_fsync_done(struct tevent_req *subreq)
2733 struct tevent_req *req = tevent_req_callback_data(
2734 subreq, struct tevent_req);
2735 struct smb_vfs_call_fsync_state *state = tevent_req_data(
2736 req, struct smb_vfs_call_fsync_state);
2738 state->retval = state->recv_fn(subreq, &state->vfs_aio_state);
2739 TALLOC_FREE(subreq);
2740 if (state->retval == -1) {
2741 tevent_req_error(req, state->vfs_aio_state.error);
2744 tevent_req_done(req);
2747 int SMB_VFS_FSYNC_RECV(struct tevent_req *req, struct vfs_aio_state *vfs_aio_state)
2749 struct smb_vfs_call_fsync_state *state = tevent_req_data(
2750 req, struct smb_vfs_call_fsync_state);
2753 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
2754 tevent_req_received(req);
2757 *vfs_aio_state = state->vfs_aio_state;
2758 retval = state->retval;
2759 tevent_req_received(req);
2764 * Synchronous version of fsync, built from backend
2765 * async VFS primitives. Uses a temporary sub-event
2766 * context (NOT NESTED).
2769 int smb_vfs_fsync_sync(files_struct *fsp)
2771 TALLOC_CTX *frame = talloc_stackframe();
2772 struct tevent_req *req = NULL;
2773 struct vfs_aio_state aio_state = { 0 };
2776 struct tevent_context *ev = samba_tevent_context_init(frame);
2782 req = SMB_VFS_FSYNC_SEND(talloc_tos(), ev, fsp);
2787 ok = tevent_req_poll(req, ev);
2792 ret = SMB_VFS_FSYNC_RECV(req, &aio_state);
2797 if (aio_state.error != 0) {
2798 errno = aio_state.error;
2803 int smb_vfs_call_stat(struct vfs_handle_struct *handle,
2804 struct smb_filename *smb_fname)
2807 return handle->fns->stat_fn(handle, smb_fname);
2810 int smb_vfs_call_fstat(struct vfs_handle_struct *handle,
2811 struct files_struct *fsp, SMB_STRUCT_STAT *sbuf)
2814 return handle->fns->fstat_fn(handle, fsp, sbuf);
2817 int smb_vfs_call_lstat(struct vfs_handle_struct *handle,
2818 struct smb_filename *smb_filename)
2821 return handle->fns->lstat_fn(handle, smb_filename);
2824 uint64_t smb_vfs_call_get_alloc_size(struct vfs_handle_struct *handle,
2825 struct files_struct *fsp,
2826 const SMB_STRUCT_STAT *sbuf)
2828 VFS_FIND(get_alloc_size);
2829 return handle->fns->get_alloc_size_fn(handle, fsp, sbuf);
2832 int smb_vfs_call_unlink(struct vfs_handle_struct *handle,
2833 const struct smb_filename *smb_fname)
2836 return handle->fns->unlink_fn(handle, smb_fname);
2839 int smb_vfs_call_chmod(struct vfs_handle_struct *handle,
2840 const struct smb_filename *smb_fname,
2844 return handle->fns->chmod_fn(handle, smb_fname, mode);
2847 int smb_vfs_call_fchmod(struct vfs_handle_struct *handle,
2848 struct files_struct *fsp, mode_t mode)
2851 return handle->fns->fchmod_fn(handle, fsp, mode);
2854 int smb_vfs_call_chown(struct vfs_handle_struct *handle,
2855 const struct smb_filename *smb_fname,
2860 return handle->fns->chown_fn(handle, smb_fname, uid, gid);
2863 int smb_vfs_call_fchown(struct vfs_handle_struct *handle,
2864 struct files_struct *fsp, uid_t uid, gid_t gid)
2867 return handle->fns->fchown_fn(handle, fsp, uid, gid);
2870 int smb_vfs_call_lchown(struct vfs_handle_struct *handle,
2871 const struct smb_filename *smb_fname,
2876 return handle->fns->lchown_fn(handle, smb_fname, uid, gid);
2879 NTSTATUS vfs_chown_fsp(files_struct *fsp, uid_t uid, gid_t gid)
2882 bool as_root = false;
2885 if (fsp->fh->fd != -1) {
2887 ret = SMB_VFS_FCHOWN(fsp, uid, gid);
2889 return NT_STATUS_OK;
2891 if (ret == -1 && errno != ENOSYS) {
2892 return map_nt_error_from_unix(errno);
2896 as_root = (geteuid() == 0);
2900 * We are being asked to chown as root. Make
2901 * sure we chdir() into the path to pin it,
2902 * and always act using lchown to ensure we
2903 * don't deref any symbolic links.
2905 char *parent_dir = NULL;
2906 const char *final_component = NULL;
2907 struct smb_filename *local_smb_fname = NULL;
2908 struct smb_filename parent_dir_fname = {0};
2909 struct smb_filename *saved_dir_fname = NULL;
2911 saved_dir_fname = vfs_GetWd(talloc_tos(),fsp->conn);
2912 if (!saved_dir_fname) {
2913 status = map_nt_error_from_unix(errno);
2914 DEBUG(0,("vfs_chown_fsp: failed to get "
2915 "current working directory. Error was %s\n",
2920 if (!parent_dirname(talloc_tos(),
2921 fsp->fsp_name->base_name,
2923 &final_component)) {
2924 return NT_STATUS_NO_MEMORY;
2927 parent_dir_fname = (struct smb_filename) {
2928 .base_name = parent_dir,
2929 .flags = fsp->fsp_name->flags
2932 /* cd into the parent dir to pin it. */
2933 ret = vfs_ChDir(fsp->conn, &parent_dir_fname);
2935 return map_nt_error_from_unix(errno);
2938 local_smb_fname = synthetic_smb_fname(talloc_tos(),
2942 fsp->fsp_name->flags);
2943 if (local_smb_fname == NULL) {
2944 status = NT_STATUS_NO_MEMORY;
2948 /* Must use lstat here. */
2949 ret = SMB_VFS_LSTAT(fsp->conn, local_smb_fname);
2951 status = map_nt_error_from_unix(errno);
2955 /* Ensure it matches the fsp stat. */
2956 if (!check_same_stat(&local_smb_fname->st,
2957 &fsp->fsp_name->st)) {
2958 status = NT_STATUS_ACCESS_DENIED;
2962 ret = SMB_VFS_LCHOWN(fsp->conn,
2967 status = NT_STATUS_OK;
2969 status = map_nt_error_from_unix(errno);
2974 vfs_ChDir(fsp->conn, saved_dir_fname);
2975 TALLOC_FREE(local_smb_fname);
2976 TALLOC_FREE(saved_dir_fname);
2977 TALLOC_FREE(parent_dir);
2982 if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) {
2983 ret = SMB_VFS_LCHOWN(fsp->conn,
2987 ret = SMB_VFS_CHOWN(fsp->conn,
2993 status = NT_STATUS_OK;
2995 status = map_nt_error_from_unix(errno);
3000 int smb_vfs_call_chdir(struct vfs_handle_struct *handle,
3001 const struct smb_filename *smb_fname)
3004 return handle->fns->chdir_fn(handle, smb_fname);
3007 struct smb_filename *smb_vfs_call_getwd(struct vfs_handle_struct *handle,
3011 return handle->fns->getwd_fn(handle, ctx);
3014 int smb_vfs_call_ntimes(struct vfs_handle_struct *handle,
3015 const struct smb_filename *smb_fname,
3016 struct smb_file_time *ft)
3019 return handle->fns->ntimes_fn(handle, smb_fname, ft);
3022 int smb_vfs_call_ftruncate(struct vfs_handle_struct *handle,
3023 struct files_struct *fsp, off_t offset)
3025 VFS_FIND(ftruncate);
3026 return handle->fns->ftruncate_fn(handle, fsp, offset);
3029 int smb_vfs_call_fallocate(struct vfs_handle_struct *handle,
3030 struct files_struct *fsp,
3035 VFS_FIND(fallocate);
3036 return handle->fns->fallocate_fn(handle, fsp, mode, offset, len);
3039 int smb_vfs_call_kernel_flock(struct vfs_handle_struct *handle,
3040 struct files_struct *fsp, uint32_t share_mode,
3041 uint32_t access_mask)
3043 VFS_FIND(kernel_flock);
3044 return handle->fns->kernel_flock_fn(handle, fsp, share_mode,
3048 int smb_vfs_call_linux_setlease(struct vfs_handle_struct *handle,
3049 struct files_struct *fsp, int leasetype)
3051 VFS_FIND(linux_setlease);
3052 return handle->fns->linux_setlease_fn(handle, fsp, leasetype);
3055 int smb_vfs_call_symlink(struct vfs_handle_struct *handle,
3056 const char *link_target,
3057 const struct smb_filename *new_smb_fname)
3060 return handle->fns->symlink_fn(handle, link_target, new_smb_fname);
3063 int smb_vfs_call_readlink(struct vfs_handle_struct *handle,
3064 const struct smb_filename *smb_fname,
3069 return handle->fns->readlink_fn(handle, smb_fname, buf, bufsiz);
3072 int smb_vfs_call_link(struct vfs_handle_struct *handle,
3073 const struct smb_filename *old_smb_fname,
3074 const struct smb_filename *new_smb_fname)
3077 return handle->fns->link_fn(handle, old_smb_fname, new_smb_fname);
3080 int smb_vfs_call_mknod(struct vfs_handle_struct *handle,
3081 const struct smb_filename *smb_fname,
3086 return handle->fns->mknod_fn(handle, smb_fname, mode, dev);
3089 struct smb_filename *smb_vfs_call_realpath(struct vfs_handle_struct *handle,
3091 const struct smb_filename *smb_fname)
3094 return handle->fns->realpath_fn(handle, ctx, smb_fname);
3097 int smb_vfs_call_chflags(struct vfs_handle_struct *handle,
3098 const struct smb_filename *smb_fname,
3102 return handle->fns->chflags_fn(handle, smb_fname, flags);
3105 struct file_id smb_vfs_call_file_id_create(struct vfs_handle_struct *handle,
3106 const SMB_STRUCT_STAT *sbuf)
3108 VFS_FIND(file_id_create);
3109 return handle->fns->file_id_create_fn(handle, sbuf);
3112 NTSTATUS smb_vfs_call_streaminfo(struct vfs_handle_struct *handle,
3113 struct files_struct *fsp,
3114 const struct smb_filename *smb_fname,
3115 TALLOC_CTX *mem_ctx,
3116 unsigned int *num_streams,
3117 struct stream_struct **streams)
3119 VFS_FIND(streaminfo);
3120 return handle->fns->streaminfo_fn(handle, fsp, smb_fname, mem_ctx,
3121 num_streams, streams);
3124 int smb_vfs_call_get_real_filename(struct vfs_handle_struct *handle,
3125 const char *path, const char *name,
3126 TALLOC_CTX *mem_ctx, char **found_name)
3128 VFS_FIND(get_real_filename);
3129 return handle->fns->get_real_filename_fn(handle, path, name, mem_ctx,
3133 const char *smb_vfs_call_connectpath(struct vfs_handle_struct *handle,
3134 const struct smb_filename *smb_fname)
3136 VFS_FIND(connectpath);
3137 return handle->fns->connectpath_fn(handle, smb_fname);
3140 bool smb_vfs_call_strict_lock_check(struct vfs_handle_struct *handle,
3141 struct files_struct *fsp,
3142 struct lock_struct *plock)
3144 VFS_FIND(strict_lock_check);
3145 return handle->fns->strict_lock_check_fn(handle, fsp, plock);
3148 NTSTATUS smb_vfs_call_translate_name(struct vfs_handle_struct *handle,
3150 enum vfs_translate_direction direction,
3151 TALLOC_CTX *mem_ctx,
3154 VFS_FIND(translate_name);
3155 return handle->fns->translate_name_fn(handle, name, direction, mem_ctx,
3159 NTSTATUS smb_vfs_call_fsctl(struct vfs_handle_struct *handle,
3160 struct files_struct *fsp,
3164 const uint8_t *in_data,
3167 uint32_t max_out_len,
3171 return handle->fns->fsctl_fn(handle, fsp, ctx, function, req_flags,
3172 in_data, in_len, out_data, max_out_len,
3176 NTSTATUS smb_vfs_call_get_dos_attributes(struct vfs_handle_struct *handle,
3177 struct smb_filename *smb_fname,
3180 VFS_FIND(get_dos_attributes);
3181 return handle->fns->get_dos_attributes_fn(handle, smb_fname, dosmode);
3184 NTSTATUS smb_vfs_call_fget_dos_attributes(struct vfs_handle_struct *handle,
3185 struct files_struct *fsp,
3188 VFS_FIND(fget_dos_attributes);
3189 return handle->fns->fget_dos_attributes_fn(handle, fsp, dosmode);
3192 NTSTATUS smb_vfs_call_set_dos_attributes(struct vfs_handle_struct *handle,
3193 const struct smb_filename *smb_fname,
3196 VFS_FIND(set_dos_attributes);
3197 return handle->fns->set_dos_attributes_fn(handle, smb_fname, dosmode);
3200 NTSTATUS smb_vfs_call_fset_dos_attributes(struct vfs_handle_struct *handle,
3201 struct files_struct *fsp,
3204 VFS_FIND(set_dos_attributes);
3205 return handle->fns->fset_dos_attributes_fn(handle, fsp, dosmode);
3208 struct tevent_req *smb_vfs_call_offload_read_send(TALLOC_CTX *mem_ctx,
3209 struct tevent_context *ev,
3210 struct vfs_handle_struct *handle,
3211 struct files_struct *fsp,
3217 VFS_FIND(offload_read_send);
3218 return handle->fns->offload_read_send_fn(mem_ctx, ev, handle,
3220 ttl, offset, to_copy);
3223 NTSTATUS smb_vfs_call_offload_read_recv(struct tevent_req *req,
3224 struct vfs_handle_struct *handle,
3225 TALLOC_CTX *mem_ctx,
3226 DATA_BLOB *token_blob)
3228 VFS_FIND(offload_read_recv);
3229 return handle->fns->offload_read_recv_fn(req, handle, mem_ctx, token_blob);
3232 struct tevent_req *smb_vfs_call_offload_write_send(struct vfs_handle_struct *handle,
3233 TALLOC_CTX *mem_ctx,
3234 struct tevent_context *ev,
3237 off_t transfer_offset,
3238 struct files_struct *dest_fsp,
3242 VFS_FIND(offload_write_send);
3243 return handle->fns->offload_write_send_fn(handle, mem_ctx, ev, fsctl,
3244 token, transfer_offset,
3245 dest_fsp, dest_off, num);
3248 NTSTATUS smb_vfs_call_offload_write_recv(struct vfs_handle_struct *handle,
3249 struct tevent_req *req,
3252 VFS_FIND(offload_write_recv);
3253 return handle->fns->offload_write_recv_fn(handle, req, copied);
3256 struct smb_vfs_call_get_dos_attributes_state {
3257 NTSTATUS (*recv_fn)(struct tevent_req *req,
3258 struct vfs_aio_state *aio_state,
3260 struct vfs_aio_state aio_state;
3261 uint32_t dos_attributes;
3264 static void smb_vfs_call_get_dos_attributes_done(struct tevent_req *subreq);
3266 struct tevent_req *smb_vfs_call_get_dos_attributes_send(
3267 TALLOC_CTX *mem_ctx,
3268 const struct smb_vfs_ev_glue *evg,
3269 struct vfs_handle_struct *handle,
3270 files_struct *dir_fsp,
3271 struct smb_filename *smb_fname)
3273 struct tevent_req *req = NULL;
3274 struct smb_vfs_call_get_dos_attributes_state *state = NULL;
3275 struct tevent_req *subreq = NULL;
3278 req = tevent_req_create(mem_ctx, &state,
3279 struct smb_vfs_call_get_dos_attributes_state);
3284 VFS_FIND(get_dos_attributes_send);
3285 state->recv_fn = handle->fns->get_dos_attributes_recv_fn;
3287 ok = smb_vfs_ev_glue_push_use(evg, req);
3289 tevent_req_error(req, EIO);
3290 return tevent_req_post(req, evg->return_ev);
3293 subreq = handle->fns->get_dos_attributes_send_fn(mem_ctx,
3298 smb_vfs_ev_glue_pop_use(evg);
3300 if (tevent_req_nomem(subreq, req)) {
3301 return tevent_req_post(req, evg->return_ev);
3303 tevent_req_set_callback(subreq,
3304 smb_vfs_call_get_dos_attributes_done,
3310 static void smb_vfs_call_get_dos_attributes_done(struct tevent_req *subreq)
3312 struct tevent_req *req =
3313 tevent_req_callback_data(subreq,
3315 struct smb_vfs_call_get_dos_attributes_state *state =
3316 tevent_req_data(req,
3317 struct smb_vfs_call_get_dos_attributes_state);
3320 status = state->recv_fn(subreq,
3322 &state->dos_attributes);
3323 TALLOC_FREE(subreq);
3324 if (tevent_req_nterror(req, status)) {
3328 tevent_req_done(req);
3331 NTSTATUS smb_vfs_call_get_dos_attributes_recv(
3332 struct tevent_req *req,
3333 struct vfs_aio_state *aio_state,
3334 uint32_t *dos_attributes)
3336 struct smb_vfs_call_get_dos_attributes_state *state =
3337 tevent_req_data(req,
3338 struct smb_vfs_call_get_dos_attributes_state);
3341 if (tevent_req_is_nterror(req, &status)) {
3342 tevent_req_received(req);
3346 *aio_state = state->aio_state;
3347 *dos_attributes = state->dos_attributes;
3348 tevent_req_received(req);
3349 return NT_STATUS_OK;
3352 NTSTATUS smb_vfs_call_get_compression(vfs_handle_struct *handle,
3353 TALLOC_CTX *mem_ctx,
3354 struct files_struct *fsp,
3355 struct smb_filename *smb_fname,
3356 uint16_t *_compression_fmt)
3358 VFS_FIND(get_compression);
3359 return handle->fns->get_compression_fn(handle, mem_ctx, fsp, smb_fname,
3363 NTSTATUS smb_vfs_call_set_compression(vfs_handle_struct *handle,
3364 TALLOC_CTX *mem_ctx,
3365 struct files_struct *fsp,
3366 uint16_t compression_fmt)
3368 VFS_FIND(set_compression);
3369 return handle->fns->set_compression_fn(handle, mem_ctx, fsp,
3373 NTSTATUS smb_vfs_call_snap_check_path(vfs_handle_struct *handle,
3374 TALLOC_CTX *mem_ctx,
3375 const char *service_path,
3378 VFS_FIND(snap_check_path);
3379 return handle->fns->snap_check_path_fn(handle, mem_ctx, service_path,
3383 NTSTATUS smb_vfs_call_snap_create(struct vfs_handle_struct *handle,
3384 TALLOC_CTX *mem_ctx,
3385 const char *base_volume,
3391 VFS_FIND(snap_create);
3392 return handle->fns->snap_create_fn(handle, mem_ctx, base_volume, tstamp,
3393 rw, base_path, snap_path);
3396 NTSTATUS smb_vfs_call_snap_delete(struct vfs_handle_struct *handle,
3397 TALLOC_CTX *mem_ctx,
3401 VFS_FIND(snap_delete);
3402 return handle->fns->snap_delete_fn(handle, mem_ctx, base_path,
3406 NTSTATUS smb_vfs_call_fget_nt_acl(struct vfs_handle_struct *handle,
3407 struct files_struct *fsp,
3408 uint32_t security_info,
3409 TALLOC_CTX *mem_ctx,
3410 struct security_descriptor **ppdesc)
3412 VFS_FIND(fget_nt_acl);
3413 return handle->fns->fget_nt_acl_fn(handle, fsp, security_info,
3417 NTSTATUS smb_vfs_call_get_nt_acl(struct vfs_handle_struct *handle,
3418 const struct smb_filename *smb_fname,
3419 uint32_t security_info,
3420 TALLOC_CTX *mem_ctx,
3421 struct security_descriptor **ppdesc)
3423 VFS_FIND(get_nt_acl);
3424 return handle->fns->get_nt_acl_fn(handle,
3431 NTSTATUS smb_vfs_call_fset_nt_acl(struct vfs_handle_struct *handle,
3432 struct files_struct *fsp,
3433 uint32_t security_info_sent,
3434 const struct security_descriptor *psd)
3436 VFS_FIND(fset_nt_acl);
3437 return handle->fns->fset_nt_acl_fn(handle, fsp, security_info_sent,
3441 NTSTATUS smb_vfs_call_audit_file(struct vfs_handle_struct *handle,
3442 struct smb_filename *file,
3443 struct security_acl *sacl,
3444 uint32_t access_requested,
3445 uint32_t access_denied)
3447 VFS_FIND(audit_file);
3448 return handle->fns->audit_file_fn(handle,
3455 SMB_ACL_T smb_vfs_call_sys_acl_get_file(struct vfs_handle_struct *handle,
3456 const struct smb_filename *smb_fname,
3457 SMB_ACL_TYPE_T type,
3458 TALLOC_CTX *mem_ctx)
3460 VFS_FIND(sys_acl_get_file);
3461 return handle->fns->sys_acl_get_file_fn(handle, smb_fname, type, mem_ctx);
3464 SMB_ACL_T smb_vfs_call_sys_acl_get_fd(struct vfs_handle_struct *handle,
3465 struct files_struct *fsp,
3466 TALLOC_CTX *mem_ctx)
3468 VFS_FIND(sys_acl_get_fd);
3469 return handle->fns->sys_acl_get_fd_fn(handle, fsp, mem_ctx);
3472 int smb_vfs_call_sys_acl_blob_get_file(struct vfs_handle_struct *handle,
3473 const struct smb_filename *smb_fname,
3474 TALLOC_CTX *mem_ctx,
3475 char **blob_description,
3478 VFS_FIND(sys_acl_blob_get_file);
3479 return handle->fns->sys_acl_blob_get_file_fn(handle, smb_fname,
3480 mem_ctx, blob_description, blob);
3483 int smb_vfs_call_sys_acl_blob_get_fd(struct vfs_handle_struct *handle,
3484 struct files_struct *fsp,
3485 TALLOC_CTX *mem_ctx,
3486 char **blob_description,
3489 VFS_FIND(sys_acl_blob_get_fd);
3490 return handle->fns->sys_acl_blob_get_fd_fn(handle, fsp, mem_ctx, blob_description, blob);
3493 int smb_vfs_call_sys_acl_set_file(struct vfs_handle_struct *handle,
3494 const struct smb_filename *smb_fname,
3495 SMB_ACL_TYPE_T acltype,
3498 VFS_FIND(sys_acl_set_file);
3499 return handle->fns->sys_acl_set_file_fn(handle, smb_fname,
3503 int smb_vfs_call_sys_acl_set_fd(struct vfs_handle_struct *handle,
3504 struct files_struct *fsp, SMB_ACL_T theacl)
3506 VFS_FIND(sys_acl_set_fd);
3507 return handle->fns->sys_acl_set_fd_fn(handle, fsp, theacl);
3510 int smb_vfs_call_sys_acl_delete_def_file(struct vfs_handle_struct *handle,
3511 const struct smb_filename *smb_fname)
3513 VFS_FIND(sys_acl_delete_def_file);
3514 return handle->fns->sys_acl_delete_def_file_fn(handle, smb_fname);
3517 ssize_t smb_vfs_call_getxattr(struct vfs_handle_struct *handle,
3518 const struct smb_filename *smb_fname,
3524 return handle->fns->getxattr_fn(handle, smb_fname, name, value, size);
3528 struct smb_vfs_call_getxattrat_state {
3529 ssize_t (*recv_fn)(struct tevent_req *req,
3530 struct vfs_aio_state *aio_state,
3531 TALLOC_CTX *mem_ctx,
3532 uint8_t **xattr_value);
3534 uint8_t *xattr_value;
3535 struct vfs_aio_state aio_state;
3538 static void smb_vfs_call_getxattrat_done(struct tevent_req *subreq);
3540 struct tevent_req *smb_vfs_call_getxattrat_send(
3541 TALLOC_CTX *mem_ctx,
3542 const struct smb_vfs_ev_glue *evg,
3543 struct vfs_handle_struct *handle,
3544 files_struct *dir_fsp,
3545 const struct smb_filename *smb_fname,
3546 const char *xattr_name,
3549 struct tevent_req *req = NULL;
3550 struct smb_vfs_call_getxattrat_state *state = NULL;
3551 struct tevent_req *subreq = NULL;
3554 req = tevent_req_create(mem_ctx, &state,
3555 struct smb_vfs_call_getxattrat_state);
3560 VFS_FIND(getxattrat_send);
3561 state->recv_fn = handle->fns->getxattrat_recv_fn;
3563 ok = smb_vfs_ev_glue_push_use(evg, req);
3565 tevent_req_error(req, EIO);
3566 return tevent_req_post(req, evg->return_ev);
3569 subreq = handle->fns->getxattrat_send_fn(mem_ctx,
3576 smb_vfs_ev_glue_pop_use(evg);
3578 if (tevent_req_nomem(subreq, req)) {
3579 return tevent_req_post(req, evg->return_ev);
3581 tevent_req_set_callback(subreq, smb_vfs_call_getxattrat_done, req);
3585 static void smb_vfs_call_getxattrat_done(struct tevent_req *subreq)
3587 struct tevent_req *req = tevent_req_callback_data(
3588 subreq, struct tevent_req);
3589 struct smb_vfs_call_getxattrat_state *state = tevent_req_data(
3590 req, struct smb_vfs_call_getxattrat_state);
3592 state->retval = state->recv_fn(subreq,
3595 &state->xattr_value);
3596 TALLOC_FREE(subreq);
3597 if (state->retval == -1) {
3598 tevent_req_error(req, state->aio_state.error);
3602 tevent_req_done(req);
3605 ssize_t smb_vfs_call_getxattrat_recv(struct tevent_req *req,
3606 struct vfs_aio_state *aio_state,
3607 TALLOC_CTX *mem_ctx,
3608 uint8_t **xattr_value)
3610 struct smb_vfs_call_getxattrat_state *state = tevent_req_data(
3611 req, struct smb_vfs_call_getxattrat_state);
3614 if (tevent_req_is_unix_error(req, &aio_state->error)) {
3615 tevent_req_received(req);
3619 *aio_state = state->aio_state;
3620 xattr_size = state->retval;
3621 if (xattr_value != NULL) {
3622 *xattr_value = talloc_move(mem_ctx, &state->xattr_value);
3625 tevent_req_received(req);
3629 ssize_t smb_vfs_call_fgetxattr(struct vfs_handle_struct *handle,
3630 struct files_struct *fsp, const char *name,
3631 void *value, size_t size)
3633 VFS_FIND(fgetxattr);
3634 return handle->fns->fgetxattr_fn(handle, fsp, name, value, size);
3637 ssize_t smb_vfs_call_listxattr(struct vfs_handle_struct *handle,
3638 const struct smb_filename *smb_fname,
3642 VFS_FIND(listxattr);
3643 return handle->fns->listxattr_fn(handle, smb_fname, list, size);
3646 ssize_t smb_vfs_call_flistxattr(struct vfs_handle_struct *handle,
3647 struct files_struct *fsp, char *list,
3650 VFS_FIND(flistxattr);
3651 return handle->fns->flistxattr_fn(handle, fsp, list, size);
3654 int smb_vfs_call_removexattr(struct vfs_handle_struct *handle,
3655 const struct smb_filename *smb_fname,
3658 VFS_FIND(removexattr);
3659 return handle->fns->removexattr_fn(handle, smb_fname, name);
3662 int smb_vfs_call_fremovexattr(struct vfs_handle_struct *handle,
3663 struct files_struct *fsp, const char *name)
3665 VFS_FIND(fremovexattr);
3666 return handle->fns->fremovexattr_fn(handle, fsp, name);
3669 int smb_vfs_call_setxattr(struct vfs_handle_struct *handle,
3670 const struct smb_filename *smb_fname,
3677 return handle->fns->setxattr_fn(handle, smb_fname,
3678 name, value, size, flags);
3681 int smb_vfs_call_fsetxattr(struct vfs_handle_struct *handle,
3682 struct files_struct *fsp, const char *name,
3683 const void *value, size_t size, int flags)
3685 VFS_FIND(fsetxattr);
3686 return handle->fns->fsetxattr_fn(handle, fsp, name, value, size, flags);
3689 bool smb_vfs_call_aio_force(struct vfs_handle_struct *handle,
3690 struct files_struct *fsp)
3692 VFS_FIND(aio_force);
3693 return handle->fns->aio_force_fn(handle, fsp);
3696 NTSTATUS smb_vfs_call_durable_cookie(struct vfs_handle_struct *handle,
3697 struct files_struct *fsp,
3698 TALLOC_CTX *mem_ctx,
3701 VFS_FIND(durable_cookie);
3702 return handle->fns->durable_cookie_fn(handle, fsp, mem_ctx, cookie);
3705 NTSTATUS smb_vfs_call_durable_disconnect(struct vfs_handle_struct *handle,
3706 struct files_struct *fsp,
3707 const DATA_BLOB old_cookie,
3708 TALLOC_CTX *mem_ctx,
3709 DATA_BLOB *new_cookie)
3711 VFS_FIND(durable_disconnect);
3712 return handle->fns->durable_disconnect_fn(handle, fsp, old_cookie,
3713 mem_ctx, new_cookie);
3716 NTSTATUS smb_vfs_call_durable_reconnect(struct vfs_handle_struct *handle,
3717 struct smb_request *smb1req,
3718 struct smbXsrv_open *op,
3719 const DATA_BLOB old_cookie,
3720 TALLOC_CTX *mem_ctx,
3721 struct files_struct **fsp,
3722 DATA_BLOB *new_cookie)
3724 VFS_FIND(durable_reconnect);
3725 return handle->fns->durable_reconnect_fn(handle, smb1req, op,
3726 old_cookie, mem_ctx, fsp,
3730 NTSTATUS smb_vfs_call_readdir_attr(struct vfs_handle_struct *handle,
3731 const struct smb_filename *fname,
3732 TALLOC_CTX *mem_ctx,
3733 struct readdir_attr_data **attr_data)
3735 VFS_FIND(readdir_attr);
3736 return handle->fns->readdir_attr_fn(handle, fname, mem_ctx, attr_data);