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"
36 #define DBGC_CLASS DBGC_VFS
41 struct vfs_fsp_data *next;
42 struct vfs_handle_struct *owner;
43 void (*destroy)(void *p_data);
45 /* NOTE: This structure contains four pointers so that we can guarantee
46 * that the end of the structure is always both 4-byte and 8-byte aligned.
50 struct vfs_init_function_entry {
52 struct vfs_init_function_entry *prev, *next;
53 const struct vfs_fn_pointers *fns;
56 /****************************************************************************
57 maintain the list of available backends
58 ****************************************************************************/
60 static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name)
62 struct vfs_init_function_entry *entry = backends;
64 DEBUG(10, ("vfs_find_backend_entry called for %s\n", name));
67 if (strcmp(entry->name, name)==0) return entry;
74 NTSTATUS smb_register_vfs(int version, const char *name,
75 const struct vfs_fn_pointers *fns)
77 struct vfs_init_function_entry *entry = backends;
79 if ((version != SMB_VFS_INTERFACE_VERSION)) {
80 DEBUG(0, ("Failed to register vfs module.\n"
81 "The module was compiled against SMB_VFS_INTERFACE_VERSION %d,\n"
82 "current SMB_VFS_INTERFACE_VERSION is %d.\n"
83 "Please recompile against the current Samba Version!\n",
84 version, SMB_VFS_INTERFACE_VERSION));
85 return NT_STATUS_OBJECT_TYPE_MISMATCH;
88 if (!name || !name[0]) {
89 DEBUG(0,("smb_register_vfs() called with NULL pointer or empty name!\n"));
90 return NT_STATUS_INVALID_PARAMETER;
93 if (vfs_find_backend_entry(name)) {
94 DEBUG(0,("VFS module %s already loaded!\n", name));
95 return NT_STATUS_OBJECT_NAME_COLLISION;
98 entry = SMB_XMALLOC_P(struct vfs_init_function_entry);
99 entry->name = smb_xstrdup(name);
102 DLIST_ADD(backends, entry);
103 DEBUG(5, ("Successfully added vfs backend '%s'\n", name));
107 /****************************************************************************
108 initialise default vfs hooks
109 ****************************************************************************/
111 static void vfs_init_default(connection_struct *conn)
113 DEBUG(3, ("Initialising default vfs hooks\n"));
114 vfs_init_custom(conn, DEFAULT_VFS_MODULE_NAME);
117 /****************************************************************************
118 initialise custom vfs hooks
119 ****************************************************************************/
121 bool vfs_init_custom(connection_struct *conn, const char *vfs_object)
123 char *module_path = NULL;
124 char *module_name = NULL;
125 char *module_param = NULL, *p;
126 vfs_handle_struct *handle;
127 const struct vfs_init_function_entry *entry;
129 if (!conn||!vfs_object||!vfs_object[0]) {
130 DEBUG(0, ("vfs_init_custom() called with NULL pointer or "
131 "empty vfs_object!\n"));
136 static_init_vfs(NULL);
139 DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object));
141 module_path = smb_xstrdup(vfs_object);
143 p = strchr_m(module_path, ':');
148 trim_char(module_param, ' ', ' ');
151 trim_char(module_path, ' ', ' ');
153 module_name = smb_xstrdup(module_path);
155 if ((module_name[0] == '/') &&
156 (strcmp(module_path, DEFAULT_VFS_MODULE_NAME) != 0)) {
159 * Extract the module name from the path. Just use the base
160 * name of the last path component.
163 SAFE_FREE(module_name);
164 module_name = smb_xstrdup(strrchr_m(module_path, '/')+1);
166 p = strchr_m(module_name, '.');
173 /* First, try to load the module with the new module system */
174 entry = vfs_find_backend_entry(module_name);
178 DEBUG(5, ("vfs module [%s] not loaded - trying to load...\n",
181 status = smb_load_module("vfs", module_path);
182 if (!NT_STATUS_IS_OK(status)) {
183 DEBUG(0, ("error probing vfs module '%s': %s\n",
184 module_path, nt_errstr(status)));
188 entry = vfs_find_backend_entry(module_name);
190 DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
195 DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
197 handle = talloc_zero(conn, vfs_handle_struct);
199 DEBUG(0,("TALLOC_ZERO() failed!\n"));
203 handle->fns = entry->fns;
205 handle->param = talloc_strdup(conn, module_param);
207 DLIST_ADD(conn->vfs_handles, handle);
209 SAFE_FREE(module_path);
210 SAFE_FREE(module_name);
214 SAFE_FREE(module_path);
215 SAFE_FREE(module_name);
219 /*****************************************************************
220 Allow VFS modules to extend files_struct with VFS-specific state.
221 This will be ok for small numbers of extensions, but might need to
222 be refactored if it becomes more widely used.
223 ******************************************************************/
225 #define EXT_DATA_AREA(e) ((uint8_t *)(e) + sizeof(struct vfs_fsp_data))
227 void *vfs_add_fsp_extension_notype(vfs_handle_struct *handle,
228 files_struct *fsp, size_t ext_size,
229 void (*destroy_fn)(void *p_data))
231 struct vfs_fsp_data *ext;
234 /* Prevent VFS modules adding multiple extensions. */
235 if ((ext_data = vfs_fetch_fsp_extension(handle, fsp))) {
239 ext = (struct vfs_fsp_data *)TALLOC_ZERO(
240 handle->conn, sizeof(struct vfs_fsp_data) + ext_size);
246 ext->next = fsp->vfs_extension;
247 ext->destroy = destroy_fn;
248 fsp->vfs_extension = ext;
249 return EXT_DATA_AREA(ext);
252 void vfs_remove_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
254 struct vfs_fsp_data *curr;
255 struct vfs_fsp_data *prev;
257 for (curr = fsp->vfs_extension, prev = NULL;
259 prev = curr, curr = curr->next) {
260 if (curr->owner == handle) {
262 prev->next = curr->next;
264 fsp->vfs_extension = curr->next;
267 curr->destroy(EXT_DATA_AREA(curr));
275 void vfs_remove_all_fsp_extensions(files_struct *fsp)
277 struct vfs_fsp_data *curr;
278 struct vfs_fsp_data *next;
280 for (curr = fsp->vfs_extension; curr; curr = next) {
283 fsp->vfs_extension = next;
286 curr->destroy(EXT_DATA_AREA(curr));
292 void *vfs_memctx_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
294 struct vfs_fsp_data *head;
296 for (head = fsp->vfs_extension; head; head = head->next) {
297 if (head->owner == handle) {
305 void *vfs_fetch_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
307 struct vfs_fsp_data *head;
309 head = (struct vfs_fsp_data *)vfs_memctx_fsp_extension(handle, fsp);
311 return EXT_DATA_AREA(head);
320 * Ensure this module catches all VFS functions.
323 void smb_vfs_assert_all_fns(const struct vfs_fn_pointers* fns,
326 bool missing_fn = false;
328 const uintptr_t *end = (const uintptr_t *)(fns + 1);
330 for (idx = 0; ((const uintptr_t *)fns + idx) < end; idx++) {
331 if (*((const uintptr_t *)fns + idx) == 0) {
332 DBG_ERR("VFS function at index %d not implemented "
333 "in module %s\n", idx, module);
339 smb_panic("Required VFS function not implemented in module.\n");
343 void smb_vfs_assert_all_fns(const struct vfs_fn_pointers* fns,
349 /*****************************************************************
351 ******************************************************************/
353 bool smbd_vfs_init(connection_struct *conn)
355 const char **vfs_objects;
359 /* Normal share - initialise with disk access functions */
360 vfs_init_default(conn);
362 /* No need to load vfs modules for printer connections */
367 vfs_objects = lp_vfs_objects(SNUM(conn));
369 /* Override VFS functions if 'vfs object' was not specified*/
370 if (!vfs_objects || !vfs_objects[0])
373 for (i=0; vfs_objects[i] ;) {
377 for (j=i-1; j >= 0; j--) {
378 if (!vfs_init_custom(conn, vfs_objects[j])) {
379 DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects[j]));
386 /*******************************************************************
387 Check if a file exists in the vfs.
388 ********************************************************************/
390 NTSTATUS vfs_file_exist(connection_struct *conn, struct smb_filename *smb_fname)
392 /* Only return OK if stat was successful and S_ISREG */
393 if ((SMB_VFS_STAT(conn, smb_fname) != -1) &&
394 S_ISREG(smb_fname->st.st_ex_mode)) {
398 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
401 ssize_t vfs_pwrite_data(struct smb_request *req,
410 if (req && req->unread_bytes) {
411 int sockfd = req->xconn->transport.sock;
412 SMB_ASSERT(req->unread_bytes == N);
413 /* VFS_RECVFILE must drain the socket
414 * before returning. */
415 req->unread_bytes = 0;
417 * Leave the socket non-blocking and
418 * use SMB_VFS_RECVFILE. If it returns
419 * EAGAIN || EWOULDBLOCK temporarily set
420 * the socket blocking and retry
424 ret = SMB_VFS_RECVFILE(sockfd,
428 if (ret == 0 || (ret == -1 &&
430 errno == EWOULDBLOCK))) {
432 /* Ensure the socket is blocking. */
433 old_flags = fcntl(sockfd, F_GETFL, 0);
434 if (set_blocking(sockfd, true) == -1) {
437 ret = SMB_VFS_RECVFILE(sockfd,
441 if (fcntl(sockfd, F_SETFL, old_flags) == -1) {
448 return (ssize_t)total;
450 /* Any other error case. */
456 return (ssize_t)total;
460 ret = SMB_VFS_PWRITE(fsp, buffer + total, N - total,
470 return (ssize_t)total;
472 /****************************************************************************
473 An allocate file space call using the vfs interface.
474 Allocates space for a file from a filedescriptor.
475 Returns 0 on success, -1 on failure.
476 ****************************************************************************/
478 int vfs_allocate_file_space(files_struct *fsp, uint64_t len)
481 connection_struct *conn = fsp->conn;
482 uint64_t space_avail;
483 uint64_t bsize,dfree,dsize;
487 * Actually try and commit the space on disk....
490 DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n",
491 fsp_str_dbg(fsp), (double)len));
493 if (((off_t)len) < 0) {
494 DEBUG(0,("vfs_allocate_file_space: %s negative len "
495 "requested.\n", fsp_str_dbg(fsp)));
500 status = vfs_stat_fsp(fsp);
501 if (!NT_STATUS_IS_OK(status)) {
505 if (len == (uint64_t)fsp->fsp_name->st.st_ex_size)
508 if (len < (uint64_t)fsp->fsp_name->st.st_ex_size) {
509 /* Shrink - use ftruncate. */
511 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current "
512 "size %.0f\n", fsp_str_dbg(fsp),
513 (double)fsp->fsp_name->st.st_ex_size));
515 contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_ALLOC_SHRINK);
517 flush_write_cache(fsp, SAMBA_SIZECHANGE_FLUSH);
518 if ((ret = SMB_VFS_FTRUNCATE(fsp, (off_t)len)) != -1) {
519 set_filelen_write_cache(fsp, len);
522 contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_ALLOC_SHRINK);
527 /* Grow - we need to test if we have enough space. */
529 contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_ALLOC_GROW);
531 if (lp_strict_allocate(SNUM(fsp->conn))) {
532 /* See if we have a syscall that will allocate beyond
533 end-of-file without changing EOF. */
534 ret = SMB_VFS_FALLOCATE(fsp, VFS_FALLOCATE_FL_KEEP_SIZE,
540 contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_ALLOC_GROW);
543 /* We changed the allocation size on disk, but not
544 EOF - exactly as required. We're done ! */
548 if (ret == -1 && errno == ENOSPC) {
552 len -= fsp->fsp_name->st.st_ex_size;
553 len /= 1024; /* Len is now number of 1k blocks needed. */
555 get_dfree_info(conn, fsp->fsp_name, &bsize, &dfree, &dsize);
556 if (space_avail == (uint64_t)-1) {
560 DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, "
561 "needed blocks = %.0f, space avail = %.0f\n",
562 fsp_str_dbg(fsp), (double)fsp->fsp_name->st.st_ex_size, (double)len,
563 (double)space_avail));
565 if (len > space_avail) {
573 /****************************************************************************
574 A vfs set_filelen call.
575 set the length of a file from a filedescriptor.
576 Returns 0 on success, -1 on failure.
577 ****************************************************************************/
579 int vfs_set_filelen(files_struct *fsp, off_t len)
583 contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_SET_FILE_LEN);
585 DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n",
586 fsp_str_dbg(fsp), (double)len));
587 flush_write_cache(fsp, SAMBA_SIZECHANGE_FLUSH);
588 if ((ret = SMB_VFS_FTRUNCATE(fsp, len)) != -1) {
589 set_filelen_write_cache(fsp, len);
590 notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
591 FILE_NOTIFY_CHANGE_SIZE
592 | FILE_NOTIFY_CHANGE_ATTRIBUTES,
593 fsp->fsp_name->base_name);
596 contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_SET_FILE_LEN);
601 /****************************************************************************
602 A slow version of fallocate. Fallback code if SMB_VFS_FALLOCATE
603 fails. Needs to be outside of the default version of SMB_VFS_FALLOCATE
604 as this is also called from the default SMB_VFS_FTRUNCATE code.
605 Always extends the file size.
606 Returns 0 on success, -1 on failure.
607 ****************************************************************************/
609 #define SPARSE_BUF_WRITE_SIZE (32*1024)
611 int vfs_slow_fallocate(files_struct *fsp, off_t offset, off_t len)
617 sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE);
624 while (total < len) {
625 size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (len - total));
627 pwrite_ret = SMB_VFS_PWRITE(fsp, sparse_buf, curr_write_size, offset + total);
628 if (pwrite_ret == -1) {
629 int saved_errno = errno;
630 DEBUG(10,("vfs_slow_fallocate: SMB_VFS_PWRITE for file "
631 "%s failed with error %s\n",
632 fsp_str_dbg(fsp), strerror(saved_errno)));
642 /****************************************************************************
643 A vfs fill sparse call.
644 Writes zeros from the end of file to len, if len is greater than EOF.
645 Used only by strict_sync.
646 Returns 0 on success, -1 on failure.
647 ****************************************************************************/
649 int vfs_fill_sparse(files_struct *fsp, off_t len)
656 status = vfs_stat_fsp(fsp);
657 if (!NT_STATUS_IS_OK(status)) {
661 if (len <= fsp->fsp_name->st.st_ex_size) {
666 if (S_ISFIFO(fsp->fsp_name->st.st_ex_mode)) {
671 DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to "
672 "len %.0f (%.0f bytes)\n", fsp_str_dbg(fsp),
673 (double)fsp->fsp_name->st.st_ex_size, (double)len,
674 (double)(len - fsp->fsp_name->st.st_ex_size)));
676 contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_FILL_SPARSE);
678 flush_write_cache(fsp, SAMBA_SIZECHANGE_FLUSH);
680 offset = fsp->fsp_name->st.st_ex_size;
681 num_to_write = len - fsp->fsp_name->st.st_ex_size;
683 /* Only do this on non-stream file handles. */
684 if (fsp->base_fsp == NULL) {
685 /* for allocation try fallocate first. This can fail on some
686 * platforms e.g. when the filesystem doesn't support it and no
687 * emulation is being done by the libc (like on AIX with JFS1). In that
688 * case we do our own emulation. fallocate implementations can
689 * return ENOTSUP or EINVAL in cases like that. */
690 ret = SMB_VFS_FALLOCATE(fsp, 0, offset, num_to_write);
691 if (ret == -1 && errno == ENOSPC) {
697 DEBUG(10,("vfs_fill_sparse: SMB_VFS_FALLOCATE failed with "
698 "error %d. Falling back to slow manual allocation\n", ret));
701 ret = vfs_slow_fallocate(fsp, offset, num_to_write);
706 set_filelen_write_cache(fsp, len);
709 contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_FILL_SPARSE);
713 /****************************************************************************
714 Transfer some data (n bytes) between two file_struct's.
715 ****************************************************************************/
717 static ssize_t vfs_pread_fn(void *file, void *buf, size_t len, off_t offset)
719 struct files_struct *fsp = (struct files_struct *)file;
721 return SMB_VFS_PREAD(fsp, buf, len, offset);
724 static ssize_t vfs_pwrite_fn(void *file, const void *buf, size_t len, off_t offset)
726 struct files_struct *fsp = (struct files_struct *)file;
728 return SMB_VFS_PWRITE(fsp, buf, len, offset);
731 off_t vfs_transfer_file(files_struct *in, files_struct *out, off_t n)
733 return transfer_file_internal((void *)in, (void *)out, n,
734 vfs_pread_fn, vfs_pwrite_fn);
737 /*******************************************************************
738 A vfs_readdir wrapper which just returns the file name.
739 ********************************************************************/
741 const char *vfs_readdirname(connection_struct *conn, void *p,
742 SMB_STRUCT_STAT *sbuf, char **talloced)
744 struct dirent *ptr= NULL;
752 ptr = SMB_VFS_READDIR(conn, (DIR *)p, sbuf);
764 #ifdef HAVE_BROKEN_READDIR_NAME
765 /* using /usr/ucb/cc is BAD */
769 status = SMB_VFS_TRANSLATE_NAME(conn, dname, vfs_translate_to_windows,
770 talloc_tos(), &translated);
771 if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
775 *talloced = translated;
776 if (!NT_STATUS_IS_OK(status)) {
782 /*******************************************************************
783 A wrapper for vfs_chdir().
784 ********************************************************************/
786 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
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);
862 if (saved_errno != 0) {
868 /*******************************************************************
869 Return the absolute current directory path - given a UNIX pathname.
870 Note that this path is returned in DOS format, not UNIX
871 format. Note this can be called with conn == NULL.
872 ********************************************************************/
874 struct smb_filename *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn)
876 struct smb_filename *current_dir_fname = NULL;
878 struct smb_filename *smb_fname_dot = NULL;
879 struct smb_filename *smb_fname_full = NULL;
880 struct smb_filename *result = NULL;
882 if (!lp_getwd_cache()) {
886 smb_fname_dot = synthetic_smb_fname(ctx, ".", NULL, NULL, 0);
887 if (smb_fname_dot == NULL) {
892 if (SMB_VFS_STAT(conn, smb_fname_dot) == -1) {
894 * Known to fail for root: the directory may be NFS-mounted
895 * and exported with root_squash (so has no root access).
897 DEBUG(1,("vfs_GetWd: couldn't stat \".\" error %s "
898 "(NFS problem ?)\n", strerror(errno) ));
902 key = vfs_file_id_from_sbuf(conn, &smb_fname_dot->st);
904 smb_fname_full = (struct smb_filename *)memcache_lookup_talloc(
907 data_blob_const(&key, sizeof(key)));
909 if (smb_fname_full == NULL) {
913 if ((SMB_VFS_STAT(conn, smb_fname_full) == 0) &&
914 (smb_fname_dot->st.st_ex_dev == smb_fname_full->st.st_ex_dev) &&
915 (smb_fname_dot->st.st_ex_ino == smb_fname_full->st.st_ex_ino) &&
916 (S_ISDIR(smb_fname_dot->st.st_ex_mode))) {
919 * Note: smb_fname_full is owned by smbd_memcache()
920 * so we must make a copy to return.
922 result = cp_smb_filename(ctx, smb_fname_full);
923 if (result == NULL) {
932 * We don't have the information to hand so rely on traditional
933 * methods. The very slow getcwd, which spawns a process on some
934 * systems, or the not quite so bad getwd.
937 current_dir_fname = SMB_VFS_GETWD(conn, ctx);
938 if (current_dir_fname == NULL) {
939 DEBUG(0, ("vfs_GetWd: SMB_VFS_GETWD call failed: %s\n",
944 if (lp_getwd_cache() && VALID_STAT(smb_fname_dot->st)) {
945 key = vfs_file_id_from_sbuf(conn, &smb_fname_dot->st);
948 * smbd_memcache() will own current_dir_fname after the
949 * memcache_add_talloc call, so we must make
950 * a copy on ctx to return.
952 result = cp_smb_filename(ctx, current_dir_fname);
953 if (result == NULL) {
958 * Ensure the memory going into the cache
959 * doesn't have a destructor so it can be
962 talloc_set_destructor(current_dir_fname, NULL);
964 memcache_add_talloc(smbd_memcache(),
966 data_blob_const(&key, sizeof(key)),
968 /* current_dir_fname is now == NULL here. */
970 /* current_dir_fname is already allocated on ctx. */
971 result = current_dir_fname;
975 TALLOC_FREE(smb_fname_dot);
977 * Don't free current_dir_fname here. It's either been moved
978 * to the memcache or is being returned in result.
983 /*******************************************************************
984 Reduce a file name, removing .. elements and checking that
985 it is below dir in the heirachy. This uses realpath.
986 This function must run as root, and will return names
987 and valid stat structs that can be checked on open.
988 ********************************************************************/
990 NTSTATUS check_reduced_name_with_privilege(connection_struct *conn,
991 const struct smb_filename *smb_fname,
992 struct smb_request *smbreq)
995 TALLOC_CTX *ctx = talloc_tos();
996 const char *conn_rootdir;
998 char *dir_name = NULL;
999 char *resolved_name = NULL;
1000 const char *last_component = NULL;
1001 struct smb_filename *resolved_fname = NULL;
1002 struct smb_filename *saved_dir_fname = NULL;
1003 struct smb_filename *smb_fname_cwd = NULL;
1004 struct privilege_paths *priv_paths = NULL;
1007 DEBUG(3,("check_reduced_name_with_privilege [%s] [%s]\n",
1008 smb_fname->base_name,
1009 conn->connectpath));
1012 priv_paths = talloc_zero(smbreq, struct privilege_paths);
1014 status = NT_STATUS_NO_MEMORY;
1018 if (!parent_dirname(ctx, smb_fname->base_name,
1019 &dir_name, &last_component)) {
1020 status = NT_STATUS_NO_MEMORY;
1024 priv_paths->parent_name.base_name = talloc_strdup(priv_paths, dir_name);
1025 priv_paths->file_name.base_name = talloc_strdup(priv_paths, last_component);
1027 if (priv_paths->parent_name.base_name == NULL ||
1028 priv_paths->file_name.base_name == NULL) {
1029 status = NT_STATUS_NO_MEMORY;
1033 if (SMB_VFS_STAT(conn, &priv_paths->parent_name) != 0) {
1034 status = map_nt_error_from_unix(errno);
1037 /* Remember where we were. */
1038 saved_dir_fname = vfs_GetWd(ctx, conn);
1039 if (!saved_dir_fname) {
1040 status = map_nt_error_from_unix(errno);
1044 if (vfs_ChDir(conn, &priv_paths->parent_name) == -1) {
1045 status = map_nt_error_from_unix(errno);
1049 smb_fname_cwd = synthetic_smb_fname(talloc_tos(), ".", NULL, NULL, 0);
1050 if (smb_fname_cwd == NULL) {
1051 status = NT_STATUS_NO_MEMORY;
1055 /* Get the absolute path of the parent directory. */
1056 resolved_fname = SMB_VFS_REALPATH(conn, ctx, smb_fname_cwd);
1057 if (resolved_fname == NULL) {
1058 status = map_nt_error_from_unix(errno);
1061 resolved_name = resolved_fname->base_name;
1063 if (*resolved_name != '/') {
1064 DEBUG(0,("check_reduced_name_with_privilege: realpath "
1065 "doesn't return absolute paths !\n"));
1066 status = NT_STATUS_OBJECT_NAME_INVALID;
1070 DEBUG(10,("check_reduced_name_with_privilege: realpath [%s] -> [%s]\n",
1071 priv_paths->parent_name.base_name,
1074 /* Now check the stat value is the same. */
1075 if (SMB_VFS_LSTAT(conn, smb_fname_cwd) != 0) {
1076 status = map_nt_error_from_unix(errno);
1080 /* Ensure we're pointing at the same place. */
1081 if (!check_same_stat(&smb_fname_cwd->st, &priv_paths->parent_name.st)) {
1082 DEBUG(0,("check_reduced_name_with_privilege: "
1083 "device/inode/uid/gid on directory %s changed. "
1084 "Denying access !\n",
1085 priv_paths->parent_name.base_name));
1086 status = NT_STATUS_ACCESS_DENIED;
1090 /* Ensure we're below the connect path. */
1092 conn_rootdir = SMB_VFS_CONNECTPATH(conn, smb_fname);
1093 if (conn_rootdir == NULL) {
1094 DEBUG(2, ("check_reduced_name_with_privilege: Could not get "
1096 status = NT_STATUS_ACCESS_DENIED;
1100 rootdir_len = strlen(conn_rootdir);
1103 * In the case of rootdir_len == 1, we know that conn_rootdir is
1104 * "/", and we also know that resolved_name starts with a slash.
1105 * So, in this corner case, resolved_name is automatically a
1106 * sub-directory of the conn_rootdir. Thus we can skip the string
1107 * comparison and the next character checks (which are even
1108 * wrong in this case).
1110 if (rootdir_len != 1) {
1113 matched = (strncmp(conn_rootdir, resolved_name,
1116 if (!matched || (resolved_name[rootdir_len] != '/' &&
1117 resolved_name[rootdir_len] != '\0')) {
1118 DEBUG(2, ("check_reduced_name_with_privilege: Bad "
1119 "access attempt: %s is a symlink outside the "
1122 DEBUGADD(2, ("conn_rootdir =%s\n", conn_rootdir));
1123 DEBUGADD(2, ("resolved_name=%s\n", resolved_name));
1124 status = NT_STATUS_ACCESS_DENIED;
1129 /* Now ensure that the last component either doesn't
1130 exist, or is *NOT* a symlink. */
1132 ret = SMB_VFS_LSTAT(conn, &priv_paths->file_name);
1134 /* Errno must be ENOENT for this be ok. */
1135 if (errno != ENOENT) {
1136 status = map_nt_error_from_unix(errno);
1137 DEBUG(2, ("check_reduced_name_with_privilege: "
1138 "LSTAT on %s failed with %s\n",
1139 priv_paths->file_name.base_name,
1140 nt_errstr(status)));
1145 if (VALID_STAT(priv_paths->file_name.st) &&
1146 S_ISLNK(priv_paths->file_name.st.st_ex_mode)) {
1147 DEBUG(2, ("check_reduced_name_with_privilege: "
1148 "Last component %s is a symlink. Denying"
1150 priv_paths->file_name.base_name));
1151 status = NT_STATUS_ACCESS_DENIED;
1155 smbreq->priv_paths = priv_paths;
1156 status = NT_STATUS_OK;
1160 if (saved_dir_fname != NULL) {
1161 vfs_ChDir(conn, saved_dir_fname);
1162 TALLOC_FREE(saved_dir_fname);
1164 TALLOC_FREE(resolved_fname);
1165 if (!NT_STATUS_IS_OK(status)) {
1166 TALLOC_FREE(priv_paths);
1168 TALLOC_FREE(dir_name);
1172 /*******************************************************************
1173 Reduce a file name, removing .. elements and checking that
1174 it is below dir in the heirachy. This uses realpath.
1176 If cwd_name == NULL then fname is a client given path relative
1177 to the root path of the share.
1179 If cwd_name != NULL then fname is a client given path relative
1180 to cwd_name. cwd_name is relative to the root path of the share.
1181 ********************************************************************/
1183 NTSTATUS check_reduced_name(connection_struct *conn,
1184 const struct smb_filename *cwd_fname,
1185 const struct smb_filename *smb_fname)
1187 TALLOC_CTX *ctx = talloc_tos();
1188 const char *cwd_name = cwd_fname ? cwd_fname->base_name : NULL;
1189 const char *fname = smb_fname->base_name;
1190 struct smb_filename *resolved_fname;
1191 char *resolved_name = NULL;
1192 char *new_fname = NULL;
1193 bool allow_symlinks = true;
1194 bool allow_widelinks = false;
1196 DBG_DEBUG("check_reduced_name [%s] [%s]\n", fname, conn->connectpath);
1198 resolved_fname = SMB_VFS_REALPATH(conn, ctx, smb_fname);
1200 if (resolved_fname == NULL) {
1203 DEBUG(3,("check_reduced_name: Component not a "
1204 "directory in getting realpath for "
1206 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1209 char *dir_name = NULL;
1210 struct smb_filename dir_fname = {0};
1211 const char *last_component = NULL;
1213 /* Last component didn't exist.
1214 Remove it and try and canonicalise
1215 the directory name. */
1216 if (!parent_dirname(ctx, fname,
1219 return NT_STATUS_NO_MEMORY;
1222 dir_fname = (struct smb_filename)
1223 { .base_name = dir_name };
1224 resolved_fname = SMB_VFS_REALPATH(conn,
1227 if (resolved_fname == NULL) {
1228 NTSTATUS status = map_nt_error_from_unix(errno);
1230 if (errno == ENOENT || errno == ENOTDIR) {
1231 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1234 DEBUG(3,("check_reduce_name: "
1235 "couldn't get realpath for "
1238 nt_errstr(status)));
1241 resolved_name = talloc_asprintf(ctx,
1243 resolved_fname->base_name,
1245 if (resolved_name == NULL) {
1246 return NT_STATUS_NO_MEMORY;
1251 DEBUG(3,("check_reduced_name: couldn't get "
1252 "realpath for %s\n", fname));
1253 return map_nt_error_from_unix(errno);
1256 resolved_name = resolved_fname->base_name;
1259 DEBUG(10,("check_reduced_name realpath [%s] -> [%s]\n", fname,
1262 if (*resolved_name != '/') {
1263 DEBUG(0,("check_reduced_name: realpath doesn't return "
1264 "absolute paths !\n"));
1265 TALLOC_FREE(resolved_fname);
1266 return NT_STATUS_OBJECT_NAME_INVALID;
1269 allow_widelinks = lp_widelinks(SNUM(conn));
1270 allow_symlinks = lp_follow_symlinks(SNUM(conn));
1272 /* Common widelinks and symlinks checks. */
1273 if (!allow_widelinks || !allow_symlinks) {
1274 const char *conn_rootdir;
1277 conn_rootdir = SMB_VFS_CONNECTPATH(conn, smb_fname);
1278 if (conn_rootdir == NULL) {
1279 DEBUG(2, ("check_reduced_name: Could not get "
1281 TALLOC_FREE(resolved_fname);
1282 return NT_STATUS_ACCESS_DENIED;
1285 rootdir_len = strlen(conn_rootdir);
1288 * In the case of rootdir_len == 1, we know that
1289 * conn_rootdir is "/", and we also know that
1290 * resolved_name starts with a slash. So, in this
1291 * corner case, resolved_name is automatically a
1292 * sub-directory of the conn_rootdir. Thus we can skip
1293 * the string comparison and the next character checks
1294 * (which are even wrong in this case).
1296 if (rootdir_len != 1) {
1299 matched = (strncmp(conn_rootdir, resolved_name,
1301 if (!matched || (resolved_name[rootdir_len] != '/' &&
1302 resolved_name[rootdir_len] != '\0')) {
1303 DEBUG(2, ("check_reduced_name: Bad access "
1304 "attempt: %s is a symlink outside the "
1305 "share path\n", fname));
1306 DEBUGADD(2, ("conn_rootdir =%s\n",
1308 DEBUGADD(2, ("resolved_name=%s\n",
1310 TALLOC_FREE(resolved_fname);
1311 return NT_STATUS_ACCESS_DENIED;
1315 /* Extra checks if all symlinks are disallowed. */
1316 if (!allow_symlinks) {
1317 /* fname can't have changed in resolved_path. */
1318 const char *p = &resolved_name[rootdir_len];
1321 * UNIX filesystem semantics, names consisting
1322 * only of "." or ".." CANNOT be symlinks.
1324 if (ISDOT(fname) || ISDOTDOT(fname)) {
1329 DEBUG(2, ("check_reduced_name: logic error (%c) "
1330 "in resolved_name: %s\n",
1333 TALLOC_FREE(resolved_fname);
1334 return NT_STATUS_ACCESS_DENIED;
1340 * If cwd_name is present and not ".",
1341 * then fname is relative to that, not
1342 * the root of the share. Make sure the
1343 * path we check is the one the client
1344 * sent (cwd_name+fname).
1346 if (cwd_name != NULL && !ISDOT(cwd_name)) {
1347 new_fname = talloc_asprintf(ctx,
1351 if (new_fname == NULL) {
1352 TALLOC_FREE(resolved_fname);
1353 return NT_STATUS_NO_MEMORY;
1358 if (strcmp(fname, p)!=0) {
1359 DEBUG(2, ("check_reduced_name: Bad access "
1360 "attempt: %s is a symlink to %s\n",
1362 TALLOC_FREE(resolved_fname);
1363 TALLOC_FREE(new_fname);
1364 return NT_STATUS_ACCESS_DENIED;
1371 DBG_INFO("%s reduced to %s\n", fname, resolved_name);
1372 TALLOC_FREE(resolved_fname);
1373 TALLOC_FREE(new_fname);
1374 return NT_STATUS_OK;
1378 * XXX: This is temporary and there should be no callers of this once
1379 * smb_filename is plumbed through all path based operations.
1381 * Called when we know stream name parsing has already been done.
1383 int vfs_stat_smb_basename(struct connection_struct *conn,
1384 const struct smb_filename *smb_fname_in,
1385 SMB_STRUCT_STAT *psbuf)
1387 struct smb_filename smb_fname = {
1388 .base_name = discard_const_p(char, smb_fname_in->base_name),
1389 .flags = smb_fname_in->flags
1393 if (smb_fname.flags & SMB_FILENAME_POSIX_PATH) {
1394 ret = SMB_VFS_LSTAT(conn, &smb_fname);
1396 ret = SMB_VFS_STAT(conn, &smb_fname);
1400 *psbuf = smb_fname.st;
1406 * Ensure LSTAT is called for POSIX paths.
1409 NTSTATUS vfs_stat_fsp(files_struct *fsp)
1413 if(fsp->fh->fd == -1) {
1414 if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) {
1415 ret = SMB_VFS_LSTAT(fsp->conn, fsp->fsp_name);
1417 ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name);
1420 return map_nt_error_from_unix(errno);
1423 if(SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st) != 0) {
1424 return map_nt_error_from_unix(errno);
1427 return NT_STATUS_OK;
1431 * Initialize num_streams and streams, then call VFS op streaminfo
1433 NTSTATUS vfs_streaminfo(connection_struct *conn,
1434 struct files_struct *fsp,
1435 const struct smb_filename *smb_fname,
1436 TALLOC_CTX *mem_ctx,
1437 unsigned int *num_streams,
1438 struct stream_struct **streams)
1442 return SMB_VFS_STREAMINFO(conn,
1451 generate a file_id from a stat structure
1453 struct file_id vfs_file_id_from_sbuf(connection_struct *conn, const SMB_STRUCT_STAT *sbuf)
1455 return SMB_VFS_FILE_ID_CREATE(conn, sbuf);
1459 * Design of the smb_vfs_ev_glue infrastructure:
1461 * smb_vfs_ev_glue makes it possible to pass
1462 * down an tevent_context and pthreadpool_tevent
1463 * used for impersonation through the SMB_VFS stack.
1465 * tevent_req based function take an tevent_context as
1466 * there 2nd argument, e.g.:
1468 * struct tevent_req *something_send(TALLOC_CTX *mem_ctx,
1469 * struct tevent_context *ev,
1472 * For the SMB_VFS stack we'll use the following:
1474 * struct tevent_req *SMB_VFS_SOMETHING_SEND(TALLOC_CTX *mem_ctx,
1475 * const struct smb_vfs_ev_glue *evg,
1478 * Typically the 'evg' is just passed through the stack down
1479 * to vfs_default.c. In order to do real work an
1480 * tevent_context and pthreadpool_tevent are required
1481 * to do call a 'somthing()' syscall in an async fashion.
1482 * Therefore it will the following to get the pointer
1485 * ev = smb_vfs_ev_glue_ev_ctx(evg);
1486 * tp = smb_vfs_ev_glue_tp_chdir_safe(evg);
1488 * If some function in the stack is sure it needs to run as root
1489 * to get some information (after careful checks!), it used
1490 * to frame that work into become_root()/unbecome_root().
1491 * This can't work when using async functions!
1492 * Now it's possible to use something like this (simplified!):
1494 * ev = smb_vfs_ev_glue_ev_ctx(evg);
1495 * root_evg = smb_vfs_ev_glue_get_root_glue(evg);
1496 * subreq = SMB_VFS_SOMETHING_NEXT_SEND(state, root_evg, ...);
1497 * if (tevent_req_nomem(subreq, req)) {
1498 * return tevent_req_post(req, ev);
1500 * tevent_req_set_callback(subreq, module_something_done, req);
1504 * static void module_something_done(struct tevent_req *subreq)
1508 * status = SMB_VFS_SOMETHING_NEXT_RECV(subreq, &state->aio_state);
1509 * TALLOC_FREE(subreq);
1511 * tevent_req_done(req);
1514 * In the code above the something_send_fn() function of the next
1515 * module in the stack will be called as root.
1516 * The smb_vfs_call_something_*() glue code, which is the magic
1517 * behind the SMB_VFS_SOMETHING[_NEXT]_{SEND,RECV}() macros,
1518 * will look like this:
1520 * struct smb_vfs_call_something_state {
1521 * ssize_t (*recv_fn)(struct tevent_req *req,
1522 * struct vfs_aio_state *aio_state,
1525 * struct vfs_aio_state vfs_aio_state;
1529 * static void smb_vfs_call_something_done(struct tevent_req *subreq);
1531 * struct tevent_req *smb_vfs_call_something_send(
1532 * TALLOC_CTX *mem_ctx,
1533 * const struct smb_vfs_ev_glue *evg,
1534 * struct vfs_handle_struct *handle,
1537 * struct tevent_req *req = NULL;
1538 * struct smb_vfs_call_something_state *state = NULL;
1539 * struct tevent_req *subreq = NULL;
1542 * req = tevent_req_create(mem_ctx, &state,
1543 * struct smb_vfs_call_something_state);
1544 * if (req == NULL) {
1548 * VFS_FIND(something_send);
1549 * state->recv_fn = handle->fns->something_recv_fn;
1551 * ok = smb_vfs_ev_glue_push_use(evg, req);
1553 * tevent_req_error(req, EIO);
1554 * return tevent_req_post(req, evg->return_ev);
1557 * subreq = handle->fns->something_send_fn(mem_ctx,
1561 * smb_vfs_ev_glue_pop_use(evg);
1563 * if (tevent_req_nomem(subreq, req)) {
1564 * return tevent_req_post(req, evg->return_ev);
1566 * tevent_req_set_callback(subreq, smb_vfs_call_something_done, req);
1571 * static void smb_vfs_call_something_done(struct tevent_req *subreq)
1573 * struct tevent_req *req =
1574 * tevent_req_callback_data(subreq,
1575 * struct tevent_req);
1576 * struct smb_vfs_call_something_state *state =
1577 * tevent_req_data(req,
1578 * struct smb_vfs_call_something_state);
1580 * state->retval = state->recv_fn(subreq,
1581 * &state->vfs_aio_state,
1583 * TALLOC_FREE(subreq);
1585 * if (state->retval == -1) {
1586 * tevent_req_error(req, state->vfs_aio_state.error);
1589 * tevent_req_done(req);
1592 * ssize_t smb_vfs_call_something_recv(struct tevent_req *req,
1593 * struct vfs_aio_state *aio_state,
1596 * struct smb_vfs_call_something_state *state =
1597 * tevent_req_data(req,
1598 * struct smb_vfs_call_something_state);
1599 * ssize_t retval = state->retval;
1601 * if (tevent_req_is_unix_error(req, &aio_state->error)) {
1602 * tevent_req_received(req);
1606 * *aio_state = state->vfs_aio_state;
1609 * tevent_req_received(req);
1613 * The most important details are these:
1615 * 1. smb_vfs_ev_glue_push_use(evg, req):
1616 * - is a no-op if evg->run_ev and evg->return_ev are the same,
1617 * it means that we're already at the correct impersonation
1618 * and don't need any additional work to be done.
1619 * - Otherwise it will call tevent_req_defer_callback(req, evg->return_ev)
1620 * This means that tevent_req_error() and tevent_req_done()
1621 * will just trigger an immediate event on evg->return_ev.
1622 * Therefore the callers callback function will be called
1623 * in the impersonation of evg->return_ev! This is important
1624 * in order to get the impersonation correct on the way back
1625 * through the stack.
1626 * - It will call tevent_context_push_use(evg->run_ev),
1627 * which will start the impersonation to run_ev.
1628 * So the following code run in the correct context.
1629 * 2. handle->fns->something_send_fn(..., evg->next_glue, ...):
1630 * - We're passing evg->next_glue to the next module.
1631 * - Typically evg->next_glue points to evg again.
1632 * - In case evg->run_ev and evg->return_ev are not the same,
1633 * next_glue will have run_ev and return_ev pointing to evg->run_ev.
1634 * So that the switch from evg->run_ev to evg->return_ev
1635 * happens on the correct boundary.
1636 * 3. smb_vfs_ev_glue_pop_use(evg):
1637 * - is a no-op if evg->run_ev and evg->return_ev are the same,
1638 * it means that we're already at the correct impersonation
1639 * and don't need any additional work to be done.
1640 * - It will call tevent_context_pop_use(evg->run_ev),
1641 * which will revert the impersonation done in
1642 * smb_vfs_ev_glue_push_use().
1643 * 4. smb_vfs_call_something_send():
1644 * - The is called in the environment of evg->return_ev.
1645 * - So it needs to use tevent_req_post(req, evg->return_ev)
1646 * 5. smb_vfs_call_something_done():
1647 * - The is called in the environment of evg->run_ev
1648 * 6. smb_vfs_call_something_recv():
1649 * - The is called in the environment of evg->return_ev again.
1652 * Here are some more complex examples:
1654 * Example 1: only user_evg without switch to root
1656 * SMBD: already impersonated user_evg
1657 * evg'1 = smb2_req->user_evg
1658 * r'1 = SMB_VFS_*_SEND(evg'1); # smb_vfs_call_*_send()
1660 * | smb_vfs_ev_glue_push_use(evg'1, r'1);
1662 * | | # no-op run_ev == return_ev
1664 * | evg'2 = evg'1->next_glue;
1665 * | r'2 = module1_*_send(evg'2);
1668 * | | r'3 = SMB_VFS_*_NEXT_SEND(evg'3); # smb_vfs_call_*_send()
1670 * | | | smb_vfs_ev_glue_push_use(evg'3, r'3);
1672 * | | | | # no-op run_ev == return_ev
1674 * | | | evg'4 = evg'3->next_glue;
1675 * | | | r'4 = module2_*_send(evg'4);
1677 * | | | | evg'5 = evg'4
1678 * | | | | r'5 = SMB_VFS_*_NEXT_SEND(evg'5); # smb_vfs_call_*_send()
1680 * | | | | | smb_vfs_ev_glue_push_use(evg'5, r'5);
1682 * | | | | | | # no-op run_ev == return_ev
1684 * | | | | | evg'6 = evg'5->next_glue;
1685 * | | | | | r'6 = default_*_send(evg'6);
1687 * | | | | | | ev'6 = smb_vfs_ev_glue_ev_ctx(evg'6)
1688 * | | | | | | tp'6 = smb_vfs_ev_glue_tp_chdir_safe(evg'6)
1689 * | | | | | | r'7 = pthreadpool_tevent_send(ev'6, tp'6);
1691 * | | | | | | | pthread_create...
1693 * | | | | | | tevent_req_set_callback(r'7, default_*_done, r'6);
1695 * | | | | | smb_vfs_ev_glue_pop_use(evg'5);
1697 * | | | | | | # no-op run_ev == return_ev
1699 * | | | | | tevent_req_set_callback(r'6, smb_vfs_call_*_done, r'5);
1701 * | | | | tevent_req_set_callback(r'5, module2_*_done, r'4);
1703 * | | | smb_vfs_ev_glue_pop_use(evg'3);
1705 * | | | | # no-op run_ev == return_ev
1707 * | | | tevent_req_set_callback(r'4, smb_vfs_call_*_done, r'3);
1709 * | | tevent_req_set_callback(r'3, module1_*_done, r'2);
1711 * | smb_vfs_ev_glue_pop_use(evg'1);
1713 * | | # no-op run_ev == return_ev
1715 * | tevent_req_set_callback(r'2, smb_vfs_call_*_done, r'1);
1717 * tevent_req_set_callback(r'1, smbd_*_done, smb2_req);
1719 * Worker thread finished, just one event handler processes
1720 * everything as there's no impersonation change.
1722 * tevent_common_invoke_immediate_handler:
1724 * | before_immediate_handler(ev'6);
1726 * | | change_to_user()
1728 * | pthreadpool_tevent_job_done(r'7);
1730 * | | default_*_done(r'7);
1732 * | | | pthreadpool_tevent_recv(r'7);
1733 * | | | TALLOC_FREE(r'7);
1734 * | | | tevent_req_done('r6);
1736 * | | | | smb_vfs_call_*_done(r'6);
1738 * | | | | | default_*_recv(r'6);
1739 * | | | | | TALLOC_FREE(r'6)
1740 * | | | | | tevent_req_done(r'5);
1742 * | | | | | | module2_*_done(r'5):
1744 * | | | | | | | SMB_VFS_*_recv(r'5); # smb_vfs_call_*_recv()
1745 * | | | | | | | TALLOC_FREE(r'5)
1746 * | | | | | | | tevent_req_done(r'4);
1748 * | | | | | | | | smb_vfs_call_*_done(r'4);
1750 * | | | | | | | | | module2_*_recv(r'4);
1751 * | | | | | | | | | TALLOC_FREE(r'4)
1752 * | | | | | | | | | tevent_req_done(r'3);
1753 * | | | | | | | | | |
1754 * | | | | | | | | | | module1_*_done(r'3):
1755 * | | | | | | | | | | |
1756 * | | | | | | | | | | | SMB_VFS_*_recv(r'3); # smb_vfs_call_*_recv()
1757 * | | | | | | | | | | | TALLOC_FREE(r'3)
1758 * | | | | | | | | | | | tevent_req_done(r'2);
1759 * | | | | | | | | | | | |
1760 * | | | | | | | | | | | | smb_vfs_*_done(r'2);
1761 * | | | | | | | | | | | | |
1762 * | | | | | | | | | | | | | module1_*_recv(r'2);
1763 * | | | | | | | | | | | | | TALLOC_FREE(r'2)
1764 * | | | | | | | | | | | | | tevent_req_done(r'1);
1765 * | | | | | | | | | | | | | |
1766 * | | | | | | | | | | | | | | smbd_*_done(r'1);
1767 * | | | | | | | | | | | | | | |
1768 * | | | | | | | | | | | | | | | SMB_VFS_*_recv(r'1); # smb_vfs_call_*_recv()
1769 * | | | | | | | | | | | | | | | TALLOC_FREE(r'1)
1770 * | | | | | | | | | | | | | | | smbd_response_to_client()
1771 * | | | | | | | | | | | | | | | return
1772 * | | | | | | | | | | | | | | |
1773 * | | | | | | | | | | | | | | return
1774 * | | | | | | | | | | | | | |
1775 * | | | | | | | | | | | | | return
1776 * | | | | | | | | | | | | |
1777 * | | | | | | | | | | | | return
1778 * | | | | | | | | | | | |
1779 * | | | | | | | | | | | return
1780 * | | | | | | | | | | |
1781 * | | | | | | | | | | return
1782 * | | | | | | | | | |
1783 * | | | | | | | | | return
1785 * | | | | | | | | return
1787 * | | | | | | | return
1789 * | | | | | | return
1799 * | after_immediate_handler(ev'6);
1801 * | | # lazy no change_to_user()
1806 * Example 2: start with user_evg and let module1 switch to root
1808 * SMBD: already impersonated user_evg
1809 * evg'1 = smb2_req->user_evg
1810 * r'1 = SMB_VFS_*_SEND(evg'1); # smb_vfs_call_*_send()
1812 * | smb_vfs_ev_glue_push_use(evg'1, r'1);
1814 * | | # no-op run_ev == return_ev
1816 * | evg'2 = evg'1->next_glue;
1817 * | r'2 = module1_*_send(evg'2);
1819 * | | evg'3 = smb_vfs_ev_glue_get_root_glue(evg'2)
1820 * | | r'3 = SMB_VFS_*_NEXT_SEND(evg'3); # smb_vfs_call_*_send()
1822 * | | | smb_vfs_ev_glue_push_use(evg'3, r'3);
1824 * | | | | tevent_req_defer_callback(r'3, evg'3->return_ev);
1825 * | | | | tevent_context_push_use(evg'3->run_ev)
1827 * | | | | | become_root()
1830 * | | | evg'4 = evg'3->next_glue;
1831 * | | | r'4 = module2_*_send(evg'4);
1833 * | | | | evg'5 = smb_vfs_ev_glue_get_root_glue(evg'4)
1834 * | | | | r'5 = SMB_VFS_*_NEXT_SEND(evg'5); # smb_vfs_call_*_send()
1836 * | | | | | smb_vfs_ev_glue_push_use(evg'5, r'5);
1838 * | | | | | | # no-op run_ev == return_ev, already root
1840 * | | | | | evg'6 = evg'5->next_glue;
1841 * | | | | | r'6 = default_*_send(evg'6);
1843 * | | | | | | ev'6 = smb_vfs_ev_glue_ev_ctx(evg'6)
1844 * | | | | | | tp'6 = smb_vfs_ev_glue_tp_chdir_safe(evg'6)
1845 * | | | | | | r'7 = pthreadpool_tevent_send(ev'6, tp'6);
1847 * | | | | | | | pthread_create...
1849 * | | | | | | tevent_req_set_callback(r'7, default_*_done, r'6);
1851 * | | | | | smb_vfs_ev_glue_pop_use(evg'5);
1853 * | | | | | | # no-op run_ev == return_ev, still stay as root
1855 * | | | | | tevent_req_set_callback(r'6, smb_vfs_*_done, r'5);
1857 * | | | | tevent_req_set_callback(r'5, module2_*_done, r'4);
1859 * | | | smb_vfs_ev_glue_pop_use(evg'3);
1861 * | | | | tevent_context_pop_use(evg'3->run_ev)
1863 * | | | | | unbecome_root()
1865 * | | | tevent_req_set_callback(r'4, smb_vfs_*_done, r'3);
1867 * | | tevent_req_set_callback(r'3, module1_*_done, r'2);
1869 * | smb_vfs_ev_glue_pop_use(evg'1);
1871 * | | # no-op run_ev == return_ev
1873 * | tevent_req_set_callback(r'2, smb_vfs_*_done, r'1);
1875 * tevent_req_set_callback(r'1, smbd_*_done, smb2_req);
1877 * Worker thread finished, just one event handler processes
1878 * everything as there's no impersonation change.
1880 * tevent_common_invoke_immediate_handler:
1882 * | before_immediate_handler(ev'6);
1886 * | pthreadpool_tevent_job_done(r'7);
1888 * | | default_*_done(r'7);
1890 * | | | pthreadpool_tevent_recv(r'7);
1891 * | | | TALLOC_FREE(r'7);
1892 * | | | tevent_req_done('r6);
1894 * | | | | smb_vfs_*_done(r'6);
1896 * | | | | | default_*_recv(r'6);
1897 * | | | | | TALLOC_FREE(r'6)
1898 * | | | | | tevent_req_done(r'5);
1900 * | | | | | | module2_*_done(r'5):
1902 * | | | | | | | SMB_VFS_*_recv(r'5);
1903 * | | | | | | | TALLOC_FREE(r'5)
1904 * | | | | | | | tevent_req_done(r'4);
1906 * | | | | | | | | smb_vfs_*_done(r'4);
1908 * | | | | | | | | | module2_*_recv(r'4);
1909 * | | | | | | | | | TALLOC_FREE(r'4)
1910 * | | | | | | | | | tevent_req_done(r'3);
1911 * | | | | | | | | | | return
1912 * | | | | | | | | | |
1913 * | | | | | | | | | return
1915 * | | | | | | | | return
1917 * | | | | | | | return
1919 * | | | | | | return
1930 * | after_immediate_handler(ev'6);
1932 * | | unbecome_root()
1936 * tevent_common_invoke_immediate_handler:
1938 * | before_immediate_handler(ev'6);
1940 * | | change_to_user()
1942 * | tevent_req_trigger();
1944 * | _tevent_req_notify_callback(r'3)
1946 * | | module1_*_done(r'3):
1948 * | | | SMB_VFS_*_recv(r'3);
1949 * | | | TALLOC_FREE(r'3)
1950 * | | | tevent_req_done(r'2);
1952 * | | | | smb_vfs_*_done(r'2);
1954 * | | | | | module1_*_recv(r'2);
1955 * | | | | | TALLOC_FREE(r'2)
1956 * | | | | | tevent_req_done(r'1);
1958 * | | | | | | smbd_*_done(r'1);
1960 * | | | | | | | SMB_VFS_*_recv(r'1);
1961 * | | | | | | | TALLOC_FREE(r'1)
1962 * | | | | | | | smbd_response_to_client()
1963 * | | | | | | | return
1965 * | | | | | | return
1975 * | after_immediate_handler(ev'6);
1977 * | | # lazy no change_to_user()
1982 struct smb_vfs_ev_glue {
1984 * The event context that should be used
1985 * to report the result back.
1987 * The is basically the callers context.
1989 struct tevent_context *return_ev;
1992 * The event context and threadpool wrappers
1993 * the current context should use.
1995 * tp_fd_safe only allows fd based functions
1996 * which don't require impersonation, this
1997 * is basically the raw threadpool.
1999 * tp_path_safe allows path based functions
2000 * to be called under the correct impersonation.
2001 * But chdir/fchdir is not allowed!
2002 * Typically calls like openat() or other *at()
2005 * tp_chdir_safe is like path_safe, but also
2006 * allows chdir/fchdir to be called, the job
2007 * can safely return with a changed directory,
2008 * the threadpool wrapper takes care of
2009 * a cleanup if required.
2010 * This is needed if *at() syscalls need
2011 * to be simulated by fchdir();$syscall(),
2014 * The distinction between these threadpool
2015 * is required because of OS limitations
2017 * - only Linux supports per thread
2018 * credentials (seteuid....)
2019 * - only Linux supports a per thread
2020 * current working directory,
2021 * using unshare(CLONE_FS). But
2022 * in some constrained container
2023 * environments even that is not available
2026 * tp_fd_safe is typically the raw threadpool
2027 * without a wrapper.
2029 * On Linux tp_path_safe and tp_chdir_safe
2030 * are typically the same (if unshare(CLONE_FS) is available)
2031 * they're implemented as wrappers of the raw threadpool.
2033 * On other OSes tp_path_safe is a wrapper
2034 * arround a sync threadpool (without real threads, just blocking
2035 * the main thread), but hidden behind the pthreadpool_tevent
2036 * api in order to make the restriction transparent.
2038 * On other OSes tp_chdir_safe is a wrapper
2039 * arround a sync threadpool (without real threads, just blocking
2040 * the main thread), but hidden behind the pthreadpool_tevent
2041 * api in order to make the restriction transparent.
2042 * It just remembers/restores the current working directory,
2043 * typically using open(".", O_RDONLY | O_DIRECTORY) and fchdir().
2045 struct tevent_context *run_ev;
2046 struct pthreadpool_tevent *run_tp_fd_safe;
2047 struct pthreadpool_tevent *run_tp_path_safe;
2048 struct pthreadpool_tevent *run_tp_chdir_safe;
2051 * The glue that should be passed down
2052 * to sub request in the stack.
2054 * Typically this points to itself.
2056 * But smb_vfs_ev_glue_create_switch() allows
2057 * to create context that can switch
2058 * between two user glues.
2060 const struct smb_vfs_ev_glue *next_glue;
2063 * If some code path wants to run
2064 * some constraint code as root,
2065 * basically an async version of become_root()
2066 * and unbecome_root().
2068 * The caller can call smb_vfs_ev_glue_get_root_glue()
2069 * to get a root glue that can be passed
2070 * to the SMB_VFS_*_SEND() function that
2071 * should run as root.
2073 * Note that the callback (registered with
2074 * tevent_req_set_callback()) won't run as
2077 const struct smb_vfs_ev_glue *root_glue;
2080 static struct smb_vfs_ev_glue *smb_vfs_ev_glue_create_internal(
2081 TALLOC_CTX *mem_ctx,
2082 struct tevent_context *return_ev,
2083 struct tevent_context *run_ev,
2084 struct pthreadpool_tevent *run_tp_fd_safe,
2085 struct pthreadpool_tevent *run_tp_path_safe,
2086 struct pthreadpool_tevent *run_tp_chdir_safe)
2088 struct smb_vfs_ev_glue *evg = NULL;
2090 evg = talloc_zero(mem_ctx, struct smb_vfs_ev_glue);
2094 *evg = (struct smb_vfs_ev_glue) {
2095 .return_ev = return_ev,
2097 .run_tp_fd_safe = run_tp_fd_safe,
2098 .run_tp_path_safe = run_tp_path_safe,
2099 .run_tp_chdir_safe = run_tp_chdir_safe,
2106 struct tevent_context *smb_vfs_ev_glue_ev_ctx(const struct smb_vfs_ev_glue *evg)
2111 struct pthreadpool_tevent *smb_vfs_ev_glue_tp_fd_safe(const struct smb_vfs_ev_glue *evg)
2113 return evg->run_tp_fd_safe;
2116 struct pthreadpool_tevent *smb_vfs_ev_glue_tp_path_safe(const struct smb_vfs_ev_glue *evg)
2118 return evg->run_tp_path_safe;
2121 struct pthreadpool_tevent *smb_vfs_ev_glue_tp_chdir_safe(const struct smb_vfs_ev_glue *evg)
2123 return evg->run_tp_chdir_safe;
2126 const struct smb_vfs_ev_glue *smb_vfs_ev_glue_get_root_glue(const struct smb_vfs_ev_glue *evg)
2128 return evg->root_glue;
2131 struct smb_vfs_ev_glue *smb_vfs_ev_glue_create(TALLOC_CTX *mem_ctx,
2132 struct tevent_context *user_ev,
2133 struct pthreadpool_tevent *user_tp_fd_safe,
2134 struct pthreadpool_tevent *user_tp_path_safe,
2135 struct pthreadpool_tevent *user_tp_chdir_safe,
2136 struct tevent_context *root_ev,
2137 struct pthreadpool_tevent *root_tp_fd_safe,
2138 struct pthreadpool_tevent *root_tp_path_safe,
2139 struct pthreadpool_tevent *root_tp_chdir_safe)
2141 struct smb_vfs_ev_glue *evg_uu = NULL;
2142 struct smb_vfs_ev_glue *evg_ru = NULL;
2143 struct smb_vfs_ev_glue *evg_rr = NULL;
2146 * The top level glue (directly returned from this function).
2148 * It uses user_ev and user_tp_* only.
2150 evg_uu = smb_vfs_ev_glue_create_internal(mem_ctx,
2151 user_ev, /* return_ev */
2152 user_ev, /* run_ev */
2155 user_tp_chdir_safe);
2156 if (evg_uu == NULL) {
2161 * The first root glue (returned by smb_vfs_ev_glue_get_root_glue()).
2163 * It uses root_ev and root_tp, but user_ev as return ev,
2164 * which means that the caller's callback (registered with
2165 * tevent_req_set_callback()) will run as user_ev.
2167 evg_ru = smb_vfs_ev_glue_create_internal(evg_uu,
2168 user_ev, /* return_ev */
2169 root_ev, /* run_ev */
2172 root_tp_chdir_safe);
2173 if (evg_ru == NULL) {
2174 TALLOC_FREE(evg_uu);
2179 * The second root glue (returned by smb_vfs_ev_glue_get_root_glue() on
2180 * root glue itself. This means code can always call
2181 * smb_vfs_ev_glue_get_root_glue() and don't have to care if the
2182 * passed glue is already a root glue.
2184 * This will then recursively point to its own root_glue pointer.
2186 * It only uses root_ev and root_tp.
2188 evg_rr = smb_vfs_ev_glue_create_internal(evg_ru,
2189 root_ev, /* return_ev */
2190 root_ev, /* run_ev */
2193 root_tp_chdir_safe);
2194 if (evg_rr == NULL) {
2195 TALLOC_FREE(evg_uu);
2200 * We now setup the glue hierachie.
2202 * Search for "Design of the smb_vfs_ev_glue infrastructure" above
2203 * for a detailed description how the chain works.
2205 * "Example 2: start with user_evg and let module1 switch to root"
2206 * explains it for the root_glue chaining.
2208 evg_rr->root_glue = evg_rr;
2209 evg_ru->root_glue = evg_rr;
2210 evg_uu->root_glue = evg_ru;
2213 * As evg_ru is a boundary with
2214 * run_ev != return_ev, we need to
2215 * alter its next_glue.
2217 evg_ru->next_glue = evg_rr;
2223 * This can be used to create a temporary glue
2224 * if you need to switch between two user contexts
2226 * It's the caller's duty to make sure both
2227 * glues stay alive for the lifetime of the
2230 struct smb_vfs_ev_glue *smb_vfs_ev_glue_create_switch(
2231 TALLOC_CTX *mem_ctx,
2232 const struct smb_vfs_ev_glue *return_evg,
2233 const struct smb_vfs_ev_glue *run_evg)
2235 const struct smb_vfs_ev_glue *run_root = run_evg->root_glue;
2236 struct smb_vfs_ev_glue *evg_u = NULL;
2237 struct smb_vfs_ev_glue *evg_r = NULL;
2240 * Here we basically need to dup run_evg (and run_evg->root_glue)
2241 * and replace their return_ev with return_evg->return_ev.
2243 * We need to put the new evgs in front of the chain...
2245 evg_u = smb_vfs_ev_glue_create_internal(mem_ctx,
2246 return_evg->return_ev,
2248 run_evg->run_tp_fd_safe,
2249 run_evg->run_tp_path_safe,
2250 run_evg->run_tp_chdir_safe);
2251 if (evg_u == NULL) {
2255 evg_r = smb_vfs_ev_glue_create_internal(evg_u,
2256 return_evg->return_ev,
2258 run_root->run_tp_fd_safe,
2259 run_root->run_tp_path_safe,
2260 run_root->run_tp_chdir_safe);
2261 if (evg_r == NULL) {
2266 * evg_r is a boundary with run_ev != return_ev.
2267 * As run_root is also a boundary, we need to
2268 * use run_root->next_glue in order to get
2269 * a glue that stays as root.
2271 * The same applies to the chaining of root
2274 evg_r->next_glue = run_root->next_glue;
2275 evg_r->root_glue = run_root->root_glue;
2278 * evg_r is a boundary with run_ev != return_ev.
2279 * But run_evg is typically not a boundary,
2280 * we use it directly as next_glue.
2282 * And the root_glue is the one we constructed above.
2284 evg_u->next_glue = run_evg;
2285 evg_u->root_glue = evg_r;
2290 static bool smb_vfs_ev_glue_push_use(const struct smb_vfs_ev_glue *evg,
2291 struct tevent_req *req)
2293 if (evg->run_ev == evg->return_ev) {
2295 * We're already in the correct
2296 * impersonation environment.
2302 * Make sure that our callers callback function
2303 * will be called in the return_ev environment.
2305 tevent_req_defer_callback(req, evg->return_ev);
2308 * let the event context wrapper do
2309 * the required impersonation.
2311 return tevent_context_push_use(evg->run_ev);
2314 static void smb_vfs_ev_glue_pop_use(const struct smb_vfs_ev_glue *evg)
2316 if (evg->run_ev == evg->return_ev) {
2318 * smb_vfs_ev_glue_push_use() didn't
2319 * change the impersonation environment.
2325 * undo the impersonation
2327 tevent_context_pop_use(evg->run_ev);
2330 int smb_vfs_call_connect(struct vfs_handle_struct *handle,
2331 const char *service, const char *user)
2334 return handle->fns->connect_fn(handle, service, user);
2337 void smb_vfs_call_disconnect(struct vfs_handle_struct *handle)
2339 VFS_FIND(disconnect);
2340 handle->fns->disconnect_fn(handle);
2343 uint64_t smb_vfs_call_disk_free(struct vfs_handle_struct *handle,
2344 const struct smb_filename *smb_fname,
2349 VFS_FIND(disk_free);
2350 return handle->fns->disk_free_fn(handle, smb_fname,
2351 bsize, dfree, dsize);
2354 int smb_vfs_call_get_quota(struct vfs_handle_struct *handle,
2355 const struct smb_filename *smb_fname,
2356 enum SMB_QUOTA_TYPE qtype,
2360 VFS_FIND(get_quota);
2361 return handle->fns->get_quota_fn(handle, smb_fname, qtype, id, qt);
2364 int smb_vfs_call_set_quota(struct vfs_handle_struct *handle,
2365 enum SMB_QUOTA_TYPE qtype, unid_t id,
2368 VFS_FIND(set_quota);
2369 return handle->fns->set_quota_fn(handle, qtype, id, qt);
2372 int smb_vfs_call_get_shadow_copy_data(struct vfs_handle_struct *handle,
2373 struct files_struct *fsp,
2374 struct shadow_copy_data *shadow_copy_data,
2377 VFS_FIND(get_shadow_copy_data);
2378 return handle->fns->get_shadow_copy_data_fn(handle, fsp,
2382 int smb_vfs_call_statvfs(struct vfs_handle_struct *handle,
2383 const struct smb_filename *smb_fname,
2384 struct vfs_statvfs_struct *statbuf)
2387 return handle->fns->statvfs_fn(handle, smb_fname, statbuf);
2390 uint32_t smb_vfs_call_fs_capabilities(struct vfs_handle_struct *handle,
2391 enum timestamp_set_resolution *p_ts_res)
2393 VFS_FIND(fs_capabilities);
2394 return handle->fns->fs_capabilities_fn(handle, p_ts_res);
2397 NTSTATUS smb_vfs_call_get_dfs_referrals(struct vfs_handle_struct *handle,
2398 struct dfs_GetDFSReferral *r)
2400 VFS_FIND(get_dfs_referrals);
2401 return handle->fns->get_dfs_referrals_fn(handle, r);
2404 DIR *smb_vfs_call_opendir(struct vfs_handle_struct *handle,
2405 const struct smb_filename *smb_fname,
2407 uint32_t attributes)
2410 return handle->fns->opendir_fn(handle, smb_fname, mask, attributes);
2413 DIR *smb_vfs_call_fdopendir(struct vfs_handle_struct *handle,
2414 struct files_struct *fsp,
2416 uint32_t attributes)
2418 VFS_FIND(fdopendir);
2419 return handle->fns->fdopendir_fn(handle, fsp, mask, attributes);
2422 struct dirent *smb_vfs_call_readdir(struct vfs_handle_struct *handle,
2424 SMB_STRUCT_STAT *sbuf)
2427 return handle->fns->readdir_fn(handle, dirp, sbuf);
2430 void smb_vfs_call_seekdir(struct vfs_handle_struct *handle,
2431 DIR *dirp, long offset)
2434 handle->fns->seekdir_fn(handle, dirp, offset);
2437 long smb_vfs_call_telldir(struct vfs_handle_struct *handle,
2441 return handle->fns->telldir_fn(handle, dirp);
2444 void smb_vfs_call_rewind_dir(struct vfs_handle_struct *handle,
2447 VFS_FIND(rewind_dir);
2448 handle->fns->rewind_dir_fn(handle, dirp);
2451 int smb_vfs_call_mkdir(struct vfs_handle_struct *handle,
2452 const struct smb_filename *smb_fname,
2456 return handle->fns->mkdir_fn(handle, smb_fname, mode);
2459 int smb_vfs_call_rmdir(struct vfs_handle_struct *handle,
2460 const struct smb_filename *smb_fname)
2463 return handle->fns->rmdir_fn(handle, smb_fname);
2466 int smb_vfs_call_closedir(struct vfs_handle_struct *handle,
2470 return handle->fns->closedir_fn(handle, dir);
2473 int smb_vfs_call_open(struct vfs_handle_struct *handle,
2474 struct smb_filename *smb_fname, struct files_struct *fsp,
2475 int flags, mode_t mode)
2478 return handle->fns->open_fn(handle, smb_fname, fsp, flags, mode);
2481 NTSTATUS smb_vfs_call_create_file(struct vfs_handle_struct *handle,
2482 struct smb_request *req,
2483 uint16_t root_dir_fid,
2484 struct smb_filename *smb_fname,
2485 uint32_t access_mask,
2486 uint32_t share_access,
2487 uint32_t create_disposition,
2488 uint32_t create_options,
2489 uint32_t file_attributes,
2490 uint32_t oplock_request,
2491 struct smb2_lease *lease,
2492 uint64_t allocation_size,
2493 uint32_t private_flags,
2494 struct security_descriptor *sd,
2495 struct ea_list *ea_list,
2496 files_struct **result,
2498 const struct smb2_create_blobs *in_context_blobs,
2499 struct smb2_create_blobs *out_context_blobs)
2501 VFS_FIND(create_file);
2502 return handle->fns->create_file_fn(
2503 handle, req, root_dir_fid, smb_fname, access_mask,
2504 share_access, create_disposition, create_options,
2505 file_attributes, oplock_request, lease, allocation_size,
2506 private_flags, sd, ea_list,
2507 result, pinfo, in_context_blobs, out_context_blobs);
2510 int smb_vfs_call_close(struct vfs_handle_struct *handle,
2511 struct files_struct *fsp)
2514 return handle->fns->close_fn(handle, fsp);
2517 ssize_t smb_vfs_call_pread(struct vfs_handle_struct *handle,
2518 struct files_struct *fsp, void *data, size_t n,
2522 return handle->fns->pread_fn(handle, fsp, data, n, offset);
2525 struct smb_vfs_call_pread_state {
2526 ssize_t (*recv_fn)(struct tevent_req *req, struct vfs_aio_state *vfs_aio_state);
2528 struct vfs_aio_state vfs_aio_state;
2531 static void smb_vfs_call_pread_done(struct tevent_req *subreq);
2533 struct tevent_req *smb_vfs_call_pread_send(struct vfs_handle_struct *handle,
2534 TALLOC_CTX *mem_ctx,
2535 struct tevent_context *ev,
2536 struct files_struct *fsp,
2538 size_t n, off_t offset)
2540 struct tevent_req *req, *subreq;
2541 struct smb_vfs_call_pread_state *state;
2543 req = tevent_req_create(mem_ctx, &state,
2544 struct smb_vfs_call_pread_state);
2548 VFS_FIND(pread_send);
2549 state->recv_fn = handle->fns->pread_recv_fn;
2551 subreq = handle->fns->pread_send_fn(handle, state, ev, fsp, data, n,
2553 if (tevent_req_nomem(subreq, req)) {
2554 return tevent_req_post(req, ev);
2556 tevent_req_set_callback(subreq, smb_vfs_call_pread_done, req);
2560 static void smb_vfs_call_pread_done(struct tevent_req *subreq)
2562 struct tevent_req *req = tevent_req_callback_data(
2563 subreq, struct tevent_req);
2564 struct smb_vfs_call_pread_state *state = tevent_req_data(
2565 req, struct smb_vfs_call_pread_state);
2567 state->retval = state->recv_fn(subreq, &state->vfs_aio_state);
2568 TALLOC_FREE(subreq);
2569 if (state->retval == -1) {
2570 tevent_req_error(req, state->vfs_aio_state.error);
2573 tevent_req_done(req);
2576 ssize_t SMB_VFS_PREAD_RECV(struct tevent_req *req,
2577 struct vfs_aio_state *vfs_aio_state)
2579 struct smb_vfs_call_pread_state *state = tevent_req_data(
2580 req, struct smb_vfs_call_pread_state);
2582 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
2583 tevent_req_received(req);
2586 *vfs_aio_state = state->vfs_aio_state;
2587 tevent_req_received(req);
2588 return state->retval;
2591 ssize_t smb_vfs_call_pwrite(struct vfs_handle_struct *handle,
2592 struct files_struct *fsp, const void *data,
2593 size_t n, off_t offset)
2596 return handle->fns->pwrite_fn(handle, fsp, data, n, offset);
2599 struct smb_vfs_call_pwrite_state {
2600 ssize_t (*recv_fn)(struct tevent_req *req, struct vfs_aio_state *vfs_aio_state);
2602 struct vfs_aio_state vfs_aio_state;
2605 static void smb_vfs_call_pwrite_done(struct tevent_req *subreq);
2607 struct tevent_req *smb_vfs_call_pwrite_send(struct vfs_handle_struct *handle,
2608 TALLOC_CTX *mem_ctx,
2609 struct tevent_context *ev,
2610 struct files_struct *fsp,
2612 size_t n, off_t offset)
2614 struct tevent_req *req, *subreq;
2615 struct smb_vfs_call_pwrite_state *state;
2617 req = tevent_req_create(mem_ctx, &state,
2618 struct smb_vfs_call_pwrite_state);
2622 VFS_FIND(pwrite_send);
2623 state->recv_fn = handle->fns->pwrite_recv_fn;
2625 subreq = handle->fns->pwrite_send_fn(handle, state, ev, fsp, data, n,
2627 if (tevent_req_nomem(subreq, req)) {
2628 return tevent_req_post(req, ev);
2630 tevent_req_set_callback(subreq, smb_vfs_call_pwrite_done, req);
2634 static void smb_vfs_call_pwrite_done(struct tevent_req *subreq)
2636 struct tevent_req *req = tevent_req_callback_data(
2637 subreq, struct tevent_req);
2638 struct smb_vfs_call_pwrite_state *state = tevent_req_data(
2639 req, struct smb_vfs_call_pwrite_state);
2641 state->retval = state->recv_fn(subreq, &state->vfs_aio_state);
2642 TALLOC_FREE(subreq);
2643 if (state->retval == -1) {
2644 tevent_req_error(req, state->vfs_aio_state.error);
2647 tevent_req_done(req);
2650 ssize_t SMB_VFS_PWRITE_RECV(struct tevent_req *req,
2651 struct vfs_aio_state *vfs_aio_state)
2653 struct smb_vfs_call_pwrite_state *state = tevent_req_data(
2654 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 tevent_req_received(req);
2662 return state->retval;
2665 off_t smb_vfs_call_lseek(struct vfs_handle_struct *handle,
2666 struct files_struct *fsp, off_t offset,
2670 return handle->fns->lseek_fn(handle, fsp, offset, whence);
2673 ssize_t smb_vfs_call_sendfile(struct vfs_handle_struct *handle, int tofd,
2674 files_struct *fromfsp, const DATA_BLOB *header,
2675 off_t offset, size_t count)
2678 return handle->fns->sendfile_fn(handle, tofd, fromfsp, header, offset,
2682 ssize_t smb_vfs_call_recvfile(struct vfs_handle_struct *handle, int fromfd,
2683 files_struct *tofsp, off_t offset,
2687 return handle->fns->recvfile_fn(handle, fromfd, tofsp, offset, count);
2690 int smb_vfs_call_rename(struct vfs_handle_struct *handle,
2691 const struct smb_filename *smb_fname_src,
2692 const struct smb_filename *smb_fname_dst)
2695 return handle->fns->rename_fn(handle, smb_fname_src, smb_fname_dst);
2698 struct smb_vfs_call_fsync_state {
2699 int (*recv_fn)(struct tevent_req *req, struct vfs_aio_state *vfs_aio_state);
2701 struct vfs_aio_state vfs_aio_state;
2704 static void smb_vfs_call_fsync_done(struct tevent_req *subreq);
2706 struct tevent_req *smb_vfs_call_fsync_send(struct vfs_handle_struct *handle,
2707 TALLOC_CTX *mem_ctx,
2708 struct tevent_context *ev,
2709 struct files_struct *fsp)
2711 struct tevent_req *req, *subreq;
2712 struct smb_vfs_call_fsync_state *state;
2714 req = tevent_req_create(mem_ctx, &state,
2715 struct smb_vfs_call_fsync_state);
2719 VFS_FIND(fsync_send);
2720 state->recv_fn = handle->fns->fsync_recv_fn;
2722 subreq = handle->fns->fsync_send_fn(handle, state, ev, fsp);
2723 if (tevent_req_nomem(subreq, req)) {
2724 return tevent_req_post(req, ev);
2726 tevent_req_set_callback(subreq, smb_vfs_call_fsync_done, req);
2730 static void smb_vfs_call_fsync_done(struct tevent_req *subreq)
2732 struct tevent_req *req = tevent_req_callback_data(
2733 subreq, struct tevent_req);
2734 struct smb_vfs_call_fsync_state *state = tevent_req_data(
2735 req, struct smb_vfs_call_fsync_state);
2737 state->retval = state->recv_fn(subreq, &state->vfs_aio_state);
2738 TALLOC_FREE(subreq);
2739 if (state->retval == -1) {
2740 tevent_req_error(req, state->vfs_aio_state.error);
2743 tevent_req_done(req);
2746 int SMB_VFS_FSYNC_RECV(struct tevent_req *req, struct vfs_aio_state *vfs_aio_state)
2748 struct smb_vfs_call_fsync_state *state = tevent_req_data(
2749 req, struct smb_vfs_call_fsync_state);
2751 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
2752 tevent_req_received(req);
2755 *vfs_aio_state = state->vfs_aio_state;
2756 tevent_req_received(req);
2757 return state->retval;
2761 * Synchronous version of fsync, built from backend
2762 * async VFS primitives. Uses a temporary sub-event
2763 * context (NOT NESTED).
2766 int smb_vfs_fsync_sync(files_struct *fsp)
2768 TALLOC_CTX *frame = talloc_stackframe();
2769 struct tevent_req *req = NULL;
2770 struct vfs_aio_state aio_state = { 0 };
2773 struct tevent_context *ev = samba_tevent_context_init(frame);
2779 req = SMB_VFS_FSYNC_SEND(talloc_tos(), ev, fsp);
2784 ok = tevent_req_poll(req, ev);
2789 ret = SMB_VFS_FSYNC_RECV(req, &aio_state);
2794 if (aio_state.error != 0) {
2795 errno = aio_state.error;
2800 int smb_vfs_call_stat(struct vfs_handle_struct *handle,
2801 struct smb_filename *smb_fname)
2804 return handle->fns->stat_fn(handle, smb_fname);
2807 int smb_vfs_call_fstat(struct vfs_handle_struct *handle,
2808 struct files_struct *fsp, SMB_STRUCT_STAT *sbuf)
2811 return handle->fns->fstat_fn(handle, fsp, sbuf);
2814 int smb_vfs_call_lstat(struct vfs_handle_struct *handle,
2815 struct smb_filename *smb_filename)
2818 return handle->fns->lstat_fn(handle, smb_filename);
2821 uint64_t smb_vfs_call_get_alloc_size(struct vfs_handle_struct *handle,
2822 struct files_struct *fsp,
2823 const SMB_STRUCT_STAT *sbuf)
2825 VFS_FIND(get_alloc_size);
2826 return handle->fns->get_alloc_size_fn(handle, fsp, sbuf);
2829 int smb_vfs_call_unlink(struct vfs_handle_struct *handle,
2830 const struct smb_filename *smb_fname)
2833 return handle->fns->unlink_fn(handle, smb_fname);
2836 int smb_vfs_call_chmod(struct vfs_handle_struct *handle,
2837 const struct smb_filename *smb_fname,
2841 return handle->fns->chmod_fn(handle, smb_fname, mode);
2844 int smb_vfs_call_fchmod(struct vfs_handle_struct *handle,
2845 struct files_struct *fsp, mode_t mode)
2848 return handle->fns->fchmod_fn(handle, fsp, mode);
2851 int smb_vfs_call_chown(struct vfs_handle_struct *handle,
2852 const struct smb_filename *smb_fname,
2857 return handle->fns->chown_fn(handle, smb_fname, uid, gid);
2860 int smb_vfs_call_fchown(struct vfs_handle_struct *handle,
2861 struct files_struct *fsp, uid_t uid, gid_t gid)
2864 return handle->fns->fchown_fn(handle, fsp, uid, gid);
2867 int smb_vfs_call_lchown(struct vfs_handle_struct *handle,
2868 const struct smb_filename *smb_fname,
2873 return handle->fns->lchown_fn(handle, smb_fname, uid, gid);
2876 NTSTATUS vfs_chown_fsp(files_struct *fsp, uid_t uid, gid_t gid)
2879 bool as_root = false;
2882 if (fsp->fh->fd != -1) {
2884 ret = SMB_VFS_FCHOWN(fsp, uid, gid);
2886 return NT_STATUS_OK;
2888 if (ret == -1 && errno != ENOSYS) {
2889 return map_nt_error_from_unix(errno);
2893 as_root = (geteuid() == 0);
2897 * We are being asked to chown as root. Make
2898 * sure we chdir() into the path to pin it,
2899 * and always act using lchown to ensure we
2900 * don't deref any symbolic links.
2902 char *parent_dir = NULL;
2903 const char *final_component = NULL;
2904 struct smb_filename *local_smb_fname = NULL;
2905 struct smb_filename parent_dir_fname = {0};
2906 struct smb_filename *saved_dir_fname = NULL;
2908 saved_dir_fname = vfs_GetWd(talloc_tos(),fsp->conn);
2909 if (!saved_dir_fname) {
2910 status = map_nt_error_from_unix(errno);
2911 DEBUG(0,("vfs_chown_fsp: failed to get "
2912 "current working directory. Error was %s\n",
2917 if (!parent_dirname(talloc_tos(),
2918 fsp->fsp_name->base_name,
2920 &final_component)) {
2921 return NT_STATUS_NO_MEMORY;
2924 parent_dir_fname = (struct smb_filename) {
2925 .base_name = parent_dir,
2926 .flags = fsp->fsp_name->flags
2929 /* cd into the parent dir to pin it. */
2930 ret = vfs_ChDir(fsp->conn, &parent_dir_fname);
2932 return map_nt_error_from_unix(errno);
2935 local_smb_fname = synthetic_smb_fname(talloc_tos(),
2939 fsp->fsp_name->flags);
2940 if (local_smb_fname == NULL) {
2941 status = NT_STATUS_NO_MEMORY;
2945 /* Must use lstat here. */
2946 ret = SMB_VFS_LSTAT(fsp->conn, local_smb_fname);
2948 status = map_nt_error_from_unix(errno);
2952 /* Ensure it matches the fsp stat. */
2953 if (!check_same_stat(&local_smb_fname->st,
2954 &fsp->fsp_name->st)) {
2955 status = NT_STATUS_ACCESS_DENIED;
2959 ret = SMB_VFS_LCHOWN(fsp->conn,
2964 status = NT_STATUS_OK;
2966 status = map_nt_error_from_unix(errno);
2971 vfs_ChDir(fsp->conn, saved_dir_fname);
2972 TALLOC_FREE(local_smb_fname);
2973 TALLOC_FREE(saved_dir_fname);
2974 TALLOC_FREE(parent_dir);
2979 if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) {
2980 ret = SMB_VFS_LCHOWN(fsp->conn,
2984 ret = SMB_VFS_CHOWN(fsp->conn,
2990 status = NT_STATUS_OK;
2992 status = map_nt_error_from_unix(errno);
2997 int smb_vfs_call_chdir(struct vfs_handle_struct *handle,
2998 const struct smb_filename *smb_fname)
3001 return handle->fns->chdir_fn(handle, smb_fname);
3004 struct smb_filename *smb_vfs_call_getwd(struct vfs_handle_struct *handle,
3008 return handle->fns->getwd_fn(handle, ctx);
3011 int smb_vfs_call_ntimes(struct vfs_handle_struct *handle,
3012 const struct smb_filename *smb_fname,
3013 struct smb_file_time *ft)
3016 return handle->fns->ntimes_fn(handle, smb_fname, ft);
3019 int smb_vfs_call_ftruncate(struct vfs_handle_struct *handle,
3020 struct files_struct *fsp, off_t offset)
3022 VFS_FIND(ftruncate);
3023 return handle->fns->ftruncate_fn(handle, fsp, offset);
3026 int smb_vfs_call_fallocate(struct vfs_handle_struct *handle,
3027 struct files_struct *fsp,
3032 VFS_FIND(fallocate);
3033 return handle->fns->fallocate_fn(handle, fsp, mode, offset, len);
3036 int smb_vfs_call_kernel_flock(struct vfs_handle_struct *handle,
3037 struct files_struct *fsp, uint32_t share_mode,
3038 uint32_t access_mask)
3040 VFS_FIND(kernel_flock);
3041 return handle->fns->kernel_flock_fn(handle, fsp, share_mode,
3045 int smb_vfs_call_linux_setlease(struct vfs_handle_struct *handle,
3046 struct files_struct *fsp, int leasetype)
3048 VFS_FIND(linux_setlease);
3049 return handle->fns->linux_setlease_fn(handle, fsp, leasetype);
3052 int smb_vfs_call_symlink(struct vfs_handle_struct *handle,
3053 const char *link_target,
3054 const struct smb_filename *new_smb_fname)
3057 return handle->fns->symlink_fn(handle, link_target, new_smb_fname);
3060 int smb_vfs_call_readlink(struct vfs_handle_struct *handle,
3061 const struct smb_filename *smb_fname,
3066 return handle->fns->readlink_fn(handle, smb_fname, buf, bufsiz);
3069 int smb_vfs_call_link(struct vfs_handle_struct *handle,
3070 const struct smb_filename *old_smb_fname,
3071 const struct smb_filename *new_smb_fname)
3074 return handle->fns->link_fn(handle, old_smb_fname, new_smb_fname);
3077 int smb_vfs_call_mknod(struct vfs_handle_struct *handle,
3078 const struct smb_filename *smb_fname,
3083 return handle->fns->mknod_fn(handle, smb_fname, mode, dev);
3086 struct smb_filename *smb_vfs_call_realpath(struct vfs_handle_struct *handle,
3088 const struct smb_filename *smb_fname)
3091 return handle->fns->realpath_fn(handle, ctx, smb_fname);
3094 int smb_vfs_call_chflags(struct vfs_handle_struct *handle,
3095 const struct smb_filename *smb_fname,
3099 return handle->fns->chflags_fn(handle, smb_fname, flags);
3102 struct file_id smb_vfs_call_file_id_create(struct vfs_handle_struct *handle,
3103 const SMB_STRUCT_STAT *sbuf)
3105 VFS_FIND(file_id_create);
3106 return handle->fns->file_id_create_fn(handle, sbuf);
3109 NTSTATUS smb_vfs_call_streaminfo(struct vfs_handle_struct *handle,
3110 struct files_struct *fsp,
3111 const struct smb_filename *smb_fname,
3112 TALLOC_CTX *mem_ctx,
3113 unsigned int *num_streams,
3114 struct stream_struct **streams)
3116 VFS_FIND(streaminfo);
3117 return handle->fns->streaminfo_fn(handle, fsp, smb_fname, mem_ctx,
3118 num_streams, streams);
3121 int smb_vfs_call_get_real_filename(struct vfs_handle_struct *handle,
3122 const char *path, const char *name,
3123 TALLOC_CTX *mem_ctx, char **found_name)
3125 VFS_FIND(get_real_filename);
3126 return handle->fns->get_real_filename_fn(handle, path, name, mem_ctx,
3130 const char *smb_vfs_call_connectpath(struct vfs_handle_struct *handle,
3131 const struct smb_filename *smb_fname)
3133 VFS_FIND(connectpath);
3134 return handle->fns->connectpath_fn(handle, smb_fname);
3137 bool smb_vfs_call_strict_lock_check(struct vfs_handle_struct *handle,
3138 struct files_struct *fsp,
3139 struct lock_struct *plock)
3141 VFS_FIND(strict_lock_check);
3142 return handle->fns->strict_lock_check_fn(handle, fsp, plock);
3145 NTSTATUS smb_vfs_call_translate_name(struct vfs_handle_struct *handle,
3147 enum vfs_translate_direction direction,
3148 TALLOC_CTX *mem_ctx,
3151 VFS_FIND(translate_name);
3152 return handle->fns->translate_name_fn(handle, name, direction, mem_ctx,
3156 NTSTATUS smb_vfs_call_fsctl(struct vfs_handle_struct *handle,
3157 struct files_struct *fsp,
3161 const uint8_t *in_data,
3164 uint32_t max_out_len,
3168 return handle->fns->fsctl_fn(handle, fsp, ctx, function, req_flags,
3169 in_data, in_len, out_data, max_out_len,
3173 NTSTATUS smb_vfs_call_get_dos_attributes(struct vfs_handle_struct *handle,
3174 struct smb_filename *smb_fname,
3177 VFS_FIND(get_dos_attributes);
3178 return handle->fns->get_dos_attributes_fn(handle, smb_fname, dosmode);
3181 NTSTATUS smb_vfs_call_fget_dos_attributes(struct vfs_handle_struct *handle,
3182 struct files_struct *fsp,
3185 VFS_FIND(fget_dos_attributes);
3186 return handle->fns->fget_dos_attributes_fn(handle, fsp, dosmode);
3189 NTSTATUS smb_vfs_call_set_dos_attributes(struct vfs_handle_struct *handle,
3190 const struct smb_filename *smb_fname,
3193 VFS_FIND(set_dos_attributes);
3194 return handle->fns->set_dos_attributes_fn(handle, smb_fname, dosmode);
3197 NTSTATUS smb_vfs_call_fset_dos_attributes(struct vfs_handle_struct *handle,
3198 struct files_struct *fsp,
3201 VFS_FIND(set_dos_attributes);
3202 return handle->fns->fset_dos_attributes_fn(handle, fsp, dosmode);
3205 struct tevent_req *smb_vfs_call_offload_read_send(TALLOC_CTX *mem_ctx,
3206 struct tevent_context *ev,
3207 struct vfs_handle_struct *handle,
3208 struct files_struct *fsp,
3214 VFS_FIND(offload_read_send);
3215 return handle->fns->offload_read_send_fn(mem_ctx, ev, handle,
3217 ttl, offset, to_copy);
3220 NTSTATUS smb_vfs_call_offload_read_recv(struct tevent_req *req,
3221 struct vfs_handle_struct *handle,
3222 TALLOC_CTX *mem_ctx,
3223 DATA_BLOB *token_blob)
3225 VFS_FIND(offload_read_recv);
3226 return handle->fns->offload_read_recv_fn(req, handle, mem_ctx, token_blob);
3229 struct tevent_req *smb_vfs_call_offload_write_send(struct vfs_handle_struct *handle,
3230 TALLOC_CTX *mem_ctx,
3231 struct tevent_context *ev,
3234 off_t transfer_offset,
3235 struct files_struct *dest_fsp,
3239 VFS_FIND(offload_write_send);
3240 return handle->fns->offload_write_send_fn(handle, mem_ctx, ev, fsctl,
3241 token, transfer_offset,
3242 dest_fsp, dest_off, num);
3245 NTSTATUS smb_vfs_call_offload_write_recv(struct vfs_handle_struct *handle,
3246 struct tevent_req *req,
3249 VFS_FIND(offload_write_recv);
3250 return handle->fns->offload_write_recv_fn(handle, req, copied);
3253 NTSTATUS smb_vfs_call_get_compression(vfs_handle_struct *handle,
3254 TALLOC_CTX *mem_ctx,
3255 struct files_struct *fsp,
3256 struct smb_filename *smb_fname,
3257 uint16_t *_compression_fmt)
3259 VFS_FIND(get_compression);
3260 return handle->fns->get_compression_fn(handle, mem_ctx, fsp, smb_fname,
3264 NTSTATUS smb_vfs_call_set_compression(vfs_handle_struct *handle,
3265 TALLOC_CTX *mem_ctx,
3266 struct files_struct *fsp,
3267 uint16_t compression_fmt)
3269 VFS_FIND(set_compression);
3270 return handle->fns->set_compression_fn(handle, mem_ctx, fsp,
3274 NTSTATUS smb_vfs_call_snap_check_path(vfs_handle_struct *handle,
3275 TALLOC_CTX *mem_ctx,
3276 const char *service_path,
3279 VFS_FIND(snap_check_path);
3280 return handle->fns->snap_check_path_fn(handle, mem_ctx, service_path,
3284 NTSTATUS smb_vfs_call_snap_create(struct vfs_handle_struct *handle,
3285 TALLOC_CTX *mem_ctx,
3286 const char *base_volume,
3292 VFS_FIND(snap_create);
3293 return handle->fns->snap_create_fn(handle, mem_ctx, base_volume, tstamp,
3294 rw, base_path, snap_path);
3297 NTSTATUS smb_vfs_call_snap_delete(struct vfs_handle_struct *handle,
3298 TALLOC_CTX *mem_ctx,
3302 VFS_FIND(snap_delete);
3303 return handle->fns->snap_delete_fn(handle, mem_ctx, base_path,
3307 NTSTATUS smb_vfs_call_fget_nt_acl(struct vfs_handle_struct *handle,
3308 struct files_struct *fsp,
3309 uint32_t security_info,
3310 TALLOC_CTX *mem_ctx,
3311 struct security_descriptor **ppdesc)
3313 VFS_FIND(fget_nt_acl);
3314 return handle->fns->fget_nt_acl_fn(handle, fsp, security_info,
3318 NTSTATUS smb_vfs_call_get_nt_acl(struct vfs_handle_struct *handle,
3319 const struct smb_filename *smb_fname,
3320 uint32_t security_info,
3321 TALLOC_CTX *mem_ctx,
3322 struct security_descriptor **ppdesc)
3324 VFS_FIND(get_nt_acl);
3325 return handle->fns->get_nt_acl_fn(handle,
3332 NTSTATUS smb_vfs_call_fset_nt_acl(struct vfs_handle_struct *handle,
3333 struct files_struct *fsp,
3334 uint32_t security_info_sent,
3335 const struct security_descriptor *psd)
3337 VFS_FIND(fset_nt_acl);
3338 return handle->fns->fset_nt_acl_fn(handle, fsp, security_info_sent,
3342 NTSTATUS smb_vfs_call_audit_file(struct vfs_handle_struct *handle,
3343 struct smb_filename *file,
3344 struct security_acl *sacl,
3345 uint32_t access_requested,
3346 uint32_t access_denied)
3348 VFS_FIND(audit_file);
3349 return handle->fns->audit_file_fn(handle,
3356 SMB_ACL_T smb_vfs_call_sys_acl_get_file(struct vfs_handle_struct *handle,
3357 const struct smb_filename *smb_fname,
3358 SMB_ACL_TYPE_T type,
3359 TALLOC_CTX *mem_ctx)
3361 VFS_FIND(sys_acl_get_file);
3362 return handle->fns->sys_acl_get_file_fn(handle, smb_fname, type, mem_ctx);
3365 SMB_ACL_T smb_vfs_call_sys_acl_get_fd(struct vfs_handle_struct *handle,
3366 struct files_struct *fsp,
3367 TALLOC_CTX *mem_ctx)
3369 VFS_FIND(sys_acl_get_fd);
3370 return handle->fns->sys_acl_get_fd_fn(handle, fsp, mem_ctx);
3373 int smb_vfs_call_sys_acl_blob_get_file(struct vfs_handle_struct *handle,
3374 const struct smb_filename *smb_fname,
3375 TALLOC_CTX *mem_ctx,
3376 char **blob_description,
3379 VFS_FIND(sys_acl_blob_get_file);
3380 return handle->fns->sys_acl_blob_get_file_fn(handle, smb_fname,
3381 mem_ctx, blob_description, blob);
3384 int smb_vfs_call_sys_acl_blob_get_fd(struct vfs_handle_struct *handle,
3385 struct files_struct *fsp,
3386 TALLOC_CTX *mem_ctx,
3387 char **blob_description,
3390 VFS_FIND(sys_acl_blob_get_fd);
3391 return handle->fns->sys_acl_blob_get_fd_fn(handle, fsp, mem_ctx, blob_description, blob);
3394 int smb_vfs_call_sys_acl_set_file(struct vfs_handle_struct *handle,
3395 const struct smb_filename *smb_fname,
3396 SMB_ACL_TYPE_T acltype,
3399 VFS_FIND(sys_acl_set_file);
3400 return handle->fns->sys_acl_set_file_fn(handle, smb_fname,
3404 int smb_vfs_call_sys_acl_set_fd(struct vfs_handle_struct *handle,
3405 struct files_struct *fsp, SMB_ACL_T theacl)
3407 VFS_FIND(sys_acl_set_fd);
3408 return handle->fns->sys_acl_set_fd_fn(handle, fsp, theacl);
3411 int smb_vfs_call_sys_acl_delete_def_file(struct vfs_handle_struct *handle,
3412 const struct smb_filename *smb_fname)
3414 VFS_FIND(sys_acl_delete_def_file);
3415 return handle->fns->sys_acl_delete_def_file_fn(handle, smb_fname);
3418 ssize_t smb_vfs_call_getxattr(struct vfs_handle_struct *handle,
3419 const struct smb_filename *smb_fname,
3425 return handle->fns->getxattr_fn(handle, smb_fname, name, value, size);
3429 struct smb_vfs_call_getxattrat_state {
3430 ssize_t (*recv_fn)(struct tevent_req *req,
3431 struct vfs_aio_state *aio_state,
3432 TALLOC_CTX *mem_ctx,
3433 uint8_t **xattr_value);
3435 uint8_t *xattr_value;
3436 struct vfs_aio_state aio_state;
3439 static void smb_vfs_call_getxattrat_done(struct tevent_req *subreq);
3441 struct tevent_req *smb_vfs_call_getxattrat_send(
3442 TALLOC_CTX *mem_ctx,
3443 const struct smb_vfs_ev_glue *evg,
3444 struct vfs_handle_struct *handle,
3445 files_struct *dir_fsp,
3446 const struct smb_filename *smb_fname,
3447 const char *xattr_name,
3450 struct tevent_req *req = NULL;
3451 struct smb_vfs_call_getxattrat_state *state = NULL;
3452 struct tevent_req *subreq = NULL;
3455 req = tevent_req_create(mem_ctx, &state,
3456 struct smb_vfs_call_getxattrat_state);
3461 VFS_FIND(getxattrat_send);
3462 state->recv_fn = handle->fns->getxattrat_recv_fn;
3464 ok = smb_vfs_ev_glue_push_use(evg, req);
3466 tevent_req_error(req, EIO);
3467 return tevent_req_post(req, evg->return_ev);
3470 subreq = handle->fns->getxattrat_send_fn(mem_ctx,
3477 smb_vfs_ev_glue_pop_use(evg);
3479 if (tevent_req_nomem(subreq, req)) {
3480 return tevent_req_post(req, evg->return_ev);
3482 tevent_req_set_callback(subreq, smb_vfs_call_getxattrat_done, req);
3486 static void smb_vfs_call_getxattrat_done(struct tevent_req *subreq)
3488 struct tevent_req *req = tevent_req_callback_data(
3489 subreq, struct tevent_req);
3490 struct smb_vfs_call_getxattrat_state *state = tevent_req_data(
3491 req, struct smb_vfs_call_getxattrat_state);
3493 state->retval = state->recv_fn(subreq,
3496 &state->xattr_value);
3497 TALLOC_FREE(subreq);
3498 if (state->retval == -1) {
3499 tevent_req_error(req, state->aio_state.error);
3503 tevent_req_done(req);
3506 ssize_t smb_vfs_call_getxattrat_recv(struct tevent_req *req,
3507 struct vfs_aio_state *aio_state,
3508 TALLOC_CTX *mem_ctx,
3509 uint8_t **xattr_value)
3511 struct smb_vfs_call_getxattrat_state *state = tevent_req_data(
3512 req, struct smb_vfs_call_getxattrat_state);
3515 if (tevent_req_is_unix_error(req, &aio_state->error)) {
3516 tevent_req_received(req);
3520 *aio_state = state->aio_state;
3521 xattr_size = state->retval;
3522 if (xattr_value != NULL) {
3523 *xattr_value = talloc_move(mem_ctx, &state->xattr_value);
3526 tevent_req_received(req);
3530 ssize_t smb_vfs_call_fgetxattr(struct vfs_handle_struct *handle,
3531 struct files_struct *fsp, const char *name,
3532 void *value, size_t size)
3534 VFS_FIND(fgetxattr);
3535 return handle->fns->fgetxattr_fn(handle, fsp, name, value, size);
3538 ssize_t smb_vfs_call_listxattr(struct vfs_handle_struct *handle,
3539 const struct smb_filename *smb_fname,
3543 VFS_FIND(listxattr);
3544 return handle->fns->listxattr_fn(handle, smb_fname, list, size);
3547 ssize_t smb_vfs_call_flistxattr(struct vfs_handle_struct *handle,
3548 struct files_struct *fsp, char *list,
3551 VFS_FIND(flistxattr);
3552 return handle->fns->flistxattr_fn(handle, fsp, list, size);
3555 int smb_vfs_call_removexattr(struct vfs_handle_struct *handle,
3556 const struct smb_filename *smb_fname,
3559 VFS_FIND(removexattr);
3560 return handle->fns->removexattr_fn(handle, smb_fname, name);
3563 int smb_vfs_call_fremovexattr(struct vfs_handle_struct *handle,
3564 struct files_struct *fsp, const char *name)
3566 VFS_FIND(fremovexattr);
3567 return handle->fns->fremovexattr_fn(handle, fsp, name);
3570 int smb_vfs_call_setxattr(struct vfs_handle_struct *handle,
3571 const struct smb_filename *smb_fname,
3578 return handle->fns->setxattr_fn(handle, smb_fname,
3579 name, value, size, flags);
3582 int smb_vfs_call_fsetxattr(struct vfs_handle_struct *handle,
3583 struct files_struct *fsp, const char *name,
3584 const void *value, size_t size, int flags)
3586 VFS_FIND(fsetxattr);
3587 return handle->fns->fsetxattr_fn(handle, fsp, name, value, size, flags);
3590 bool smb_vfs_call_aio_force(struct vfs_handle_struct *handle,
3591 struct files_struct *fsp)
3593 VFS_FIND(aio_force);
3594 return handle->fns->aio_force_fn(handle, fsp);
3597 NTSTATUS smb_vfs_call_durable_cookie(struct vfs_handle_struct *handle,
3598 struct files_struct *fsp,
3599 TALLOC_CTX *mem_ctx,
3602 VFS_FIND(durable_cookie);
3603 return handle->fns->durable_cookie_fn(handle, fsp, mem_ctx, cookie);
3606 NTSTATUS smb_vfs_call_durable_disconnect(struct vfs_handle_struct *handle,
3607 struct files_struct *fsp,
3608 const DATA_BLOB old_cookie,
3609 TALLOC_CTX *mem_ctx,
3610 DATA_BLOB *new_cookie)
3612 VFS_FIND(durable_disconnect);
3613 return handle->fns->durable_disconnect_fn(handle, fsp, old_cookie,
3614 mem_ctx, new_cookie);
3617 NTSTATUS smb_vfs_call_durable_reconnect(struct vfs_handle_struct *handle,
3618 struct smb_request *smb1req,
3619 struct smbXsrv_open *op,
3620 const DATA_BLOB old_cookie,
3621 TALLOC_CTX *mem_ctx,
3622 struct files_struct **fsp,
3623 DATA_BLOB *new_cookie)
3625 VFS_FIND(durable_reconnect);
3626 return handle->fns->durable_reconnect_fn(handle, smb1req, op,
3627 old_cookie, mem_ctx, fsp,
3631 NTSTATUS smb_vfs_call_readdir_attr(struct vfs_handle_struct *handle,
3632 const struct smb_filename *fname,
3633 TALLOC_CTX *mem_ctx,
3634 struct readdir_attr_data **attr_data)
3636 VFS_FIND(readdir_attr);
3637 return handle->fns->readdir_attr_fn(handle, fname, mem_ctx, attr_data);