a6c49cfad341428eed91a6771601520399e07a4b
[samba.git] / source3 / smbd / vfs.c
1 /*
2    Unix SMB/Netbios implementation.
3    Version 1.9.
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
9
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.
14
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.
19
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/>.
22
23    This work was sponsored by Optifacio Software Services, Inc.
24 */
25
26 #include "includes.h"
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"
32 #include "ntioctl.h"
33 #include "lib/util/tevent_unix.h"
34 #include "lib/util/tevent_ntstatus.h"
35
36 #undef DBGC_CLASS
37 #define DBGC_CLASS DBGC_VFS
38
39 static_decl_vfs;
40
41 struct vfs_fsp_data {
42     struct vfs_fsp_data *next;
43     struct vfs_handle_struct *owner;
44     void (*destroy)(void *p_data);
45     void *_dummy_;
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.
48      */
49 };
50
51 struct vfs_init_function_entry {
52         char *name;
53         struct vfs_init_function_entry *prev, *next;
54         const struct vfs_fn_pointers *fns;
55 };
56
57 /****************************************************************************
58     maintain the list of available backends
59 ****************************************************************************/
60
61 static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name)
62 {
63         struct vfs_init_function_entry *entry = backends;
64
65         DEBUG(10, ("vfs_find_backend_entry called for %s\n", name));
66
67         while(entry) {
68                 if (strcmp(entry->name, name)==0) return entry;
69                 entry = entry->next;
70         }
71
72         return NULL;
73 }
74
75 NTSTATUS smb_register_vfs(int version, const char *name,
76                           const struct vfs_fn_pointers *fns)
77 {
78         struct vfs_init_function_entry *entry = backends;
79
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;
87         }
88
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;
92         }
93
94         if (vfs_find_backend_entry(name)) {
95                 DEBUG(0,("VFS module %s already loaded!\n", name));
96                 return NT_STATUS_OBJECT_NAME_COLLISION;
97         }
98
99         entry = SMB_XMALLOC_P(struct vfs_init_function_entry);
100         entry->name = smb_xstrdup(name);
101         entry->fns = fns;
102
103         DLIST_ADD(backends, entry);
104         DEBUG(5, ("Successfully added vfs backend '%s'\n", name));
105         return NT_STATUS_OK;
106 }
107
108 /****************************************************************************
109   initialise default vfs hooks
110 ****************************************************************************/
111
112 static void vfs_init_default(connection_struct *conn)
113 {
114         DEBUG(3, ("Initialising default vfs hooks\n"));
115         vfs_init_custom(conn, DEFAULT_VFS_MODULE_NAME);
116 }
117
118 /****************************************************************************
119   initialise custom vfs hooks
120  ****************************************************************************/
121
122 bool vfs_init_custom(connection_struct *conn, const char *vfs_object)
123 {
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;
129
130         if (!conn||!vfs_object||!vfs_object[0]) {
131                 DEBUG(0, ("vfs_init_custom() called with NULL pointer or "
132                           "empty vfs_object!\n"));
133                 return False;
134         }
135
136         if(!backends) {
137                 static_init_vfs(NULL);
138         }
139
140         DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object));
141
142         module_path = smb_xstrdup(vfs_object);
143
144         p = strchr_m(module_path, ':');
145
146         if (p) {
147                 *p = 0;
148                 module_param = p+1;
149                 trim_char(module_param, ' ', ' ');
150         }
151
152         trim_char(module_path, ' ', ' ');
153
154         module_name = smb_xstrdup(module_path);
155
156         if ((module_name[0] == '/') &&
157             (strcmp(module_path, DEFAULT_VFS_MODULE_NAME) != 0)) {
158
159                 /*
160                  * Extract the module name from the path. Just use the base
161                  * name of the last path component.
162                  */
163
164                 SAFE_FREE(module_name);
165                 module_name = smb_xstrdup(strrchr_m(module_path, '/')+1);
166
167                 p = strchr_m(module_name, '.');
168
169                 if (p != NULL) {
170                         *p = '\0';
171                 }
172         }
173
174         /* First, try to load the module with the new module system */
175         entry = vfs_find_backend_entry(module_name);
176         if (!entry) {
177                 NTSTATUS status;
178
179                 DEBUG(5, ("vfs module [%s] not loaded - trying to load...\n",
180                           vfs_object));
181
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)));
186                         goto fail;
187                 }
188
189                 entry = vfs_find_backend_entry(module_name);
190                 if (!entry) {
191                         DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
192                         goto fail;
193                 }
194         }
195
196         DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
197
198         handle = talloc_zero(conn, vfs_handle_struct);
199         if (!handle) {
200                 DEBUG(0,("TALLOC_ZERO() failed!\n"));
201                 goto fail;
202         }
203         handle->conn = conn;
204         handle->fns = entry->fns;
205         if (module_param) {
206                 handle->param = talloc_strdup(conn, module_param);
207         }
208         DLIST_ADD(conn->vfs_handles, handle);
209
210         SAFE_FREE(module_path);
211         SAFE_FREE(module_name);
212         return True;
213
214  fail:
215         SAFE_FREE(module_path);
216         SAFE_FREE(module_name);
217         return False;
218 }
219
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 ******************************************************************/
225
226 #define EXT_DATA_AREA(e) ((uint8_t *)(e) + sizeof(struct vfs_fsp_data))
227
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))
231 {
232         struct vfs_fsp_data *ext;
233         void * ext_data;
234
235         /* Prevent VFS modules adding multiple extensions. */
236         if ((ext_data = vfs_fetch_fsp_extension(handle, fsp))) {
237                 return ext_data;
238         }
239
240         ext = (struct vfs_fsp_data *)TALLOC_ZERO(
241                 handle->conn, sizeof(struct vfs_fsp_data) + ext_size);
242         if (ext == NULL) {
243                 return NULL;
244         }
245
246         ext->owner = handle;
247         ext->next = fsp->vfs_extension;
248         ext->destroy = destroy_fn;
249         fsp->vfs_extension = ext;
250         return EXT_DATA_AREA(ext);
251 }
252
253 void vfs_remove_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
254 {
255         struct vfs_fsp_data *curr;
256         struct vfs_fsp_data *prev;
257
258         for (curr = fsp->vfs_extension, prev = NULL;
259              curr;
260              prev = curr, curr = curr->next) {
261                 if (curr->owner == handle) {
262                     if (prev) {
263                             prev->next = curr->next;
264                     } else {
265                             fsp->vfs_extension = curr->next;
266                     }
267                     if (curr->destroy) {
268                             curr->destroy(EXT_DATA_AREA(curr));
269                     }
270                     TALLOC_FREE(curr);
271                     return;
272                 }
273         }
274 }
275
276 void vfs_remove_all_fsp_extensions(files_struct *fsp)
277 {
278         struct vfs_fsp_data *curr;
279         struct vfs_fsp_data *next;
280
281         for (curr = fsp->vfs_extension; curr; curr = next) {
282
283                 next = curr->next;
284                 fsp->vfs_extension = next;
285
286                 if (curr->destroy) {
287                         curr->destroy(EXT_DATA_AREA(curr));
288                 }
289                 TALLOC_FREE(curr);
290         }
291 }
292
293 void *vfs_memctx_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
294 {
295         struct vfs_fsp_data *head;
296
297         for (head = fsp->vfs_extension; head; head = head->next) {
298                 if (head->owner == handle) {
299                         return head;
300                 }
301         }
302
303         return NULL;
304 }
305
306 void *vfs_fetch_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
307 {
308         struct vfs_fsp_data *head;
309
310         head = (struct vfs_fsp_data *)vfs_memctx_fsp_extension(handle, fsp);
311         if (head != NULL) {
312                 return EXT_DATA_AREA(head);
313         }
314
315         return NULL;
316 }
317
318 #undef EXT_DATA_AREA
319
320 /*
321  * Ensure this module catches all VFS functions.
322  */
323 #ifdef DEVELOPER
324 void smb_vfs_assert_all_fns(const struct vfs_fn_pointers* fns,
325                             const char *module)
326 {
327         bool missing_fn = false;
328         unsigned int idx;
329         const uintptr_t *end = (const uintptr_t *)(fns + 1);
330
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);
335                         missing_fn = true;
336                 }
337         }
338
339         if (missing_fn) {
340                 smb_panic("Required VFS function not implemented in module.\n");
341         }
342 }
343 #else
344 void smb_vfs_assert_all_fns(const struct vfs_fn_pointers* fns,
345                             const char *module)
346 {
347 }
348 #endif
349
350 /*****************************************************************
351  Generic VFS init.
352 ******************************************************************/
353
354 bool smbd_vfs_init(connection_struct *conn)
355 {
356         const char **vfs_objects;
357         unsigned int i = 0;
358         int j = 0;
359
360         /* Normal share - initialise with disk access functions */
361         vfs_init_default(conn);
362
363         /* No need to load vfs modules for printer connections */
364         if (conn->printer) {
365                 return True;
366         }
367
368         vfs_objects = lp_vfs_objects(SNUM(conn));
369
370         /* Override VFS functions if 'vfs object' was not specified*/
371         if (!vfs_objects || !vfs_objects[0])
372                 return True;
373
374         for (i=0; vfs_objects[i] ;) {
375                 i++;
376         }
377
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]));
381                         return False;
382                 }
383         }
384         return True;
385 }
386
387 /*******************************************************************
388  Check if a file exists in the vfs.
389 ********************************************************************/
390
391 NTSTATUS vfs_file_exist(connection_struct *conn, struct smb_filename *smb_fname)
392 {
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)) {
396                 return NT_STATUS_OK;
397         }
398
399         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
400 }
401
402 ssize_t vfs_pwrite_data(struct smb_request *req,
403                         files_struct *fsp,
404                         const char *buffer,
405                         size_t N,
406                         off_t offset)
407 {
408         size_t total=0;
409         ssize_t ret;
410
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;
417                 /*
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
422                  * the RECVFILE.
423                  */
424                 while (total < N) {
425                         ret = SMB_VFS_RECVFILE(sockfd,
426                                                 fsp,
427                                                 offset + total,
428                                                 N - total);
429                         if (ret == 0 || (ret == -1 &&
430                                          (errno == EAGAIN ||
431                                           errno == EWOULDBLOCK))) {
432                                 int old_flags;
433                                 /* Ensure the socket is blocking. */
434                                 old_flags = fcntl(sockfd, F_GETFL, 0);
435                                 if (set_blocking(sockfd, true) == -1) {
436                                         return (ssize_t)-1;
437                                 }
438                                 ret = SMB_VFS_RECVFILE(sockfd,
439                                                         fsp,
440                                                         offset + total,
441                                                         N - total);
442                                 if (fcntl(sockfd, F_SETFL, old_flags) == -1) {
443                                         return (ssize_t)-1;
444                                 }
445                                 if (ret == -1) {
446                                         return (ssize_t)-1;
447                                 }
448                                 total += ret;
449                                 return (ssize_t)total;
450                         }
451                         /* Any other error case. */
452                         if (ret == -1) {
453                                 return ret;
454                         }
455                         total += ret;
456                 }
457                 return (ssize_t)total;
458         }
459
460         while (total < N) {
461                 ret = SMB_VFS_PWRITE(fsp, buffer + total, N - total,
462                                      offset + total);
463
464                 if (ret == -1)
465                         return -1;
466                 if (ret == 0)
467                         return total;
468
469                 total += ret;
470         }
471         return (ssize_t)total;
472 }
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 ****************************************************************************/
478
479 int vfs_allocate_file_space(files_struct *fsp, uint64_t len)
480 {
481         int ret;
482         connection_struct *conn = fsp->conn;
483         uint64_t space_avail;
484         uint64_t bsize,dfree,dsize;
485         NTSTATUS status;
486
487         /*
488          * Actually try and commit the space on disk....
489          */
490
491         DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n",
492                   fsp_str_dbg(fsp), (double)len));
493
494         if (((off_t)len) < 0) {
495                 DEBUG(0,("vfs_allocate_file_space: %s negative len "
496                          "requested.\n", fsp_str_dbg(fsp)));
497                 errno = EINVAL;
498                 return -1;
499         }
500
501         status = vfs_stat_fsp(fsp);
502         if (!NT_STATUS_IS_OK(status)) {
503                 return -1;
504         }
505
506         if (len == (uint64_t)fsp->fsp_name->st.st_ex_size)
507                 return 0;
508
509         if (len < (uint64_t)fsp->fsp_name->st.st_ex_size) {
510                 /* Shrink - use ftruncate. */
511
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));
515
516                 contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_ALLOC_SHRINK);
517
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);
521                 }
522
523                 contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_ALLOC_SHRINK);
524
525                 return ret;
526         }
527
528         /* Grow - we need to test if we have enough space. */
529
530         contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_ALLOC_GROW);
531
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,
536                                         0, len);
537         } else {
538                 ret = 0;
539         }
540
541         contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_ALLOC_GROW);
542
543         if (ret == 0) {
544                 /* We changed the allocation size on disk, but not
545                    EOF - exactly as required. We're done ! */
546                 return 0;
547         }
548
549         if (ret == -1 && errno == ENOSPC) {
550                 return -1;
551         }
552
553         len -= fsp->fsp_name->st.st_ex_size;
554         len /= 1024; /* Len is now number of 1k blocks needed. */
555         space_avail =
556             get_dfree_info(conn, fsp->fsp_name, &bsize, &dfree, &dsize);
557         if (space_avail == (uint64_t)-1) {
558                 return -1;
559         }
560
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));
565
566         if (len > space_avail) {
567                 errno = ENOSPC;
568                 return -1;
569         }
570
571         return 0;
572 }
573
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 ****************************************************************************/
579
580 int vfs_set_filelen(files_struct *fsp, off_t len)
581 {
582         int ret;
583
584         contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_SET_FILE_LEN);
585
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);
595         }
596
597         contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_SET_FILE_LEN);
598
599         return ret;
600 }
601
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 ****************************************************************************/
609
610 #define SPARSE_BUF_WRITE_SIZE (32*1024)
611
612 int vfs_slow_fallocate(files_struct *fsp, off_t offset, off_t len)
613 {
614         ssize_t pwrite_ret;
615         size_t total = 0;
616
617         if (!sparse_buf) {
618                 sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE);
619                 if (!sparse_buf) {
620                         errno = ENOMEM;
621                         return -1;
622                 }
623         }
624
625         while (total < len) {
626                 size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (len - total));
627
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)));
634                         errno = saved_errno;
635                         return -1;
636                 }
637                 total += pwrite_ret;
638         }
639
640         return 0;
641 }
642
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 ****************************************************************************/
649
650 int vfs_fill_sparse(files_struct *fsp, off_t len)
651 {
652         int ret;
653         NTSTATUS status;
654         off_t offset;
655         size_t num_to_write;
656
657         status = vfs_stat_fsp(fsp);
658         if (!NT_STATUS_IS_OK(status)) {
659                 return -1;
660         }
661
662         if (len <= fsp->fsp_name->st.st_ex_size) {
663                 return 0;
664         }
665
666 #ifdef S_ISFIFO
667         if (S_ISFIFO(fsp->fsp_name->st.st_ex_mode)) {
668                 return 0;
669         }
670 #endif
671
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)));
676
677         contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_FILL_SPARSE);
678
679         flush_write_cache(fsp, SAMBA_SIZECHANGE_FLUSH);
680
681         offset = fsp->fsp_name->st.st_ex_size;
682         num_to_write = len - fsp->fsp_name->st.st_ex_size;
683
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) {
693                         goto out;
694                 }
695                 if (ret == 0) {
696                         goto out;
697                 }
698                 DEBUG(10,("vfs_fill_sparse: SMB_VFS_FALLOCATE failed with "
699                         "error %d. Falling back to slow manual allocation\n", ret));
700         }
701
702         ret = vfs_slow_fallocate(fsp, offset, num_to_write);
703
704  out:
705
706         if (ret == 0) {
707                 set_filelen_write_cache(fsp, len);
708         }
709
710         contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_FILL_SPARSE);
711         return ret;
712 }
713
714 /****************************************************************************
715  Transfer some data (n bytes) between two file_struct's.
716 ****************************************************************************/
717
718 static ssize_t vfs_pread_fn(void *file, void *buf, size_t len, off_t offset)
719 {
720         struct files_struct *fsp = (struct files_struct *)file;
721
722         return SMB_VFS_PREAD(fsp, buf, len, offset);
723 }
724
725 static ssize_t vfs_pwrite_fn(void *file, const void *buf, size_t len, off_t offset)
726 {
727         struct files_struct *fsp = (struct files_struct *)file;
728
729         return SMB_VFS_PWRITE(fsp, buf, len, offset);
730 }
731
732 off_t vfs_transfer_file(files_struct *in, files_struct *out, off_t n)
733 {
734         return transfer_file_internal((void *)in, (void *)out, n,
735                                       vfs_pread_fn, vfs_pwrite_fn);
736 }
737
738 /*******************************************************************
739  A vfs_readdir wrapper which just returns the file name.
740 ********************************************************************/
741
742 const char *vfs_readdirname(connection_struct *conn, void *p,
743                             SMB_STRUCT_STAT *sbuf, char **talloced)
744 {
745         struct dirent *ptr= NULL;
746         const char *dname;
747         char *translated;
748         NTSTATUS status;
749
750         if (!p)
751                 return(NULL);
752
753         ptr = SMB_VFS_READDIR(conn, (DIR *)p, sbuf);
754         if (!ptr)
755                 return(NULL);
756
757         dname = ptr->d_name;
758
759
760 #ifdef NEXT2
761         if (telldir(p) < 0)
762                 return(NULL);
763 #endif
764
765 #ifdef HAVE_BROKEN_READDIR_NAME
766         /* using /usr/ucb/cc is BAD */
767         dname = dname - 2;
768 #endif
769
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)) {
773                 *talloced = NULL;
774                 return dname;
775         }
776         *talloced = translated;
777         if (!NT_STATUS_IS_OK(status)) {
778                 return NULL;
779         }
780         return translated;
781 }
782
783 /*******************************************************************
784  A wrapper for vfs_chdir().
785 ********************************************************************/
786
787 int vfs_ChDir(connection_struct *conn, const struct smb_filename *smb_fname)
788 {
789         int ret;
790         int saved_errno = 0;
791         struct smb_filename *old_cwd = conn->cwd_fname;
792
793         if (!LastDir) {
794                 LastDir = SMB_STRDUP("");
795         }
796
797         if (ISDOT(smb_fname->base_name)) {
798                 return 0;
799         }
800
801         if (*smb_fname->base_name == '/' &&
802                         strcsequal(LastDir,smb_fname->base_name)) {
803                 return 0;
804         }
805
806         DEBUG(4,("vfs_ChDir to %s\n", smb_fname->base_name));
807
808         ret = SMB_VFS_CHDIR(conn, smb_fname);
809         if (ret != 0) {
810                 return -1;
811         }
812
813         /*
814          * Always replace conn->cwd_fname. We
815          * don't know if it's been modified by
816          * VFS modules in the stack.
817          */
818
819         /* conn cache. */
820         conn->cwd_fname = vfs_GetWd(conn, conn);
821         if (conn->cwd_fname == NULL) {
822                 /*
823                  * vfs_GetWd() failed.
824                  * We must be able to read cwd.
825                  * Return to original directory
826                  * and return -1.
827                  */
828                 saved_errno = errno;
829
830                 if (old_cwd == NULL) {
831                         /*
832                          * Failed on the very first chdir()+getwd()
833                          * for this connection. We can't
834                          * continue.
835                          */
836                         smb_panic("conn->cwd getwd failed\n");
837                         /* NOTREACHED */
838                         return -1;
839                 }
840                 /* Restore original conn->cwd_fname. */
841                 conn->cwd_fname = old_cwd;
842
843                 /* Return to the previous $cwd. */
844                 ret = SMB_VFS_CHDIR(conn, conn->cwd_fname);
845                 if (ret != 0) {
846                         smb_panic("conn->cwd getwd failed\n");
847                         /* NOTREACHED */
848                         return -1;
849                 }
850                 errno = saved_errno;
851                 /* And fail the chdir(). */
852                 return -1;
853         }
854
855         /* vfs_GetWd() succeeded. */
856         /* Replace global cache. */
857         SAFE_FREE(LastDir);
858         LastDir = SMB_STRDUP(smb_fname->base_name);
859
860         DEBUG(4,("vfs_ChDir got %s\n", conn->cwd_fname->base_name));
861
862         TALLOC_FREE(old_cwd);
863         if (saved_errno != 0) {
864                 errno = saved_errno;
865         }
866         return ret;
867 }
868
869 /*******************************************************************
870  Return the absolute current directory path - given a UNIX pathname.
871  Note that this path is returned in DOS format, not UNIX
872  format. Note this can be called with conn == NULL.
873 ********************************************************************/
874
875 struct smb_filename *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn)
876 {
877         struct smb_filename *current_dir_fname = NULL;
878         struct file_id key;
879         struct smb_filename *smb_fname_dot = NULL;
880         struct smb_filename *smb_fname_full = NULL;
881         struct smb_filename *result = NULL;
882
883         if (!lp_getwd_cache()) {
884                 goto nocache;
885         }
886
887         smb_fname_dot = synthetic_smb_fname(ctx, ".", NULL, NULL, 0);
888         if (smb_fname_dot == NULL) {
889                 errno = ENOMEM;
890                 goto out;
891         }
892
893         if (SMB_VFS_STAT(conn, smb_fname_dot) == -1) {
894                 /*
895                  * Known to fail for root: the directory may be NFS-mounted
896                  * and exported with root_squash (so has no root access).
897                  */
898                 DEBUG(1,("vfs_GetWd: couldn't stat \".\" error %s "
899                          "(NFS problem ?)\n", strerror(errno) ));
900                 goto nocache;
901         }
902
903         key = vfs_file_id_from_sbuf(conn, &smb_fname_dot->st);
904
905         smb_fname_full = (struct smb_filename *)memcache_lookup_talloc(
906                                         smbd_memcache(),
907                                         GETWD_CACHE,
908                                         data_blob_const(&key, sizeof(key)));
909
910         if (smb_fname_full == NULL) {
911                 goto nocache;
912         }
913
914         if ((SMB_VFS_STAT(conn, smb_fname_full) == 0) &&
915             (smb_fname_dot->st.st_ex_dev == smb_fname_full->st.st_ex_dev) &&
916             (smb_fname_dot->st.st_ex_ino == smb_fname_full->st.st_ex_ino) &&
917             (S_ISDIR(smb_fname_dot->st.st_ex_mode))) {
918                 /*
919                  * Ok, we're done
920                  * Note: smb_fname_full is owned by smbd_memcache()
921                  * so we must make a copy to return.
922                  */
923                 result = cp_smb_filename(ctx, smb_fname_full);
924                 if (result == NULL) {
925                         errno = ENOMEM;
926                 }
927                 goto out;
928         }
929
930  nocache:
931
932         /*
933          * We don't have the information to hand so rely on traditional
934          * methods. The very slow getcwd, which spawns a process on some
935          * systems, or the not quite so bad getwd.
936          */
937
938         current_dir_fname = SMB_VFS_GETWD(conn, ctx);
939         if (current_dir_fname == NULL) {
940                 DEBUG(0, ("vfs_GetWd: SMB_VFS_GETWD call failed: %s\n",
941                           strerror(errno)));
942                 goto out;
943         }
944
945         if (lp_getwd_cache() && VALID_STAT(smb_fname_dot->st)) {
946                 key = vfs_file_id_from_sbuf(conn, &smb_fname_dot->st);
947
948                 /*
949                  * smbd_memcache() will own current_dir_fname after the
950                  * memcache_add_talloc call, so we must make
951                  * a copy on ctx to return.
952                  */
953                 result = cp_smb_filename(ctx, current_dir_fname);
954                 if (result == NULL) {
955                         errno = ENOMEM;
956                 }
957
958                 /*
959                  * Ensure the memory going into the cache
960                  * doesn't have a destructor so it can be
961                  * cleanly freed.
962                  */
963                 talloc_set_destructor(current_dir_fname, NULL);
964
965                 memcache_add_talloc(smbd_memcache(),
966                                 GETWD_CACHE,
967                                 data_blob_const(&key, sizeof(key)),
968                                 &current_dir_fname);
969                 /* current_dir_fname is now == NULL here. */
970         } else {
971                 /* current_dir_fname is already allocated on ctx. */
972                 result = current_dir_fname;
973         }
974
975  out:
976         TALLOC_FREE(smb_fname_dot);
977         /*
978          * Don't free current_dir_fname here. It's either been moved
979          * to the memcache or is being returned in result.
980          */
981         return result;
982 }
983
984 /*******************************************************************
985  Reduce a file name, removing .. elements and checking that
986  it is below dir in the heirachy. This uses realpath.
987  This function must run as root, and will return names
988  and valid stat structs that can be checked on open.
989 ********************************************************************/
990
991 NTSTATUS check_reduced_name_with_privilege(connection_struct *conn,
992                         const struct smb_filename *smb_fname,
993                         struct smb_request *smbreq)
994 {
995         NTSTATUS status;
996         TALLOC_CTX *ctx = talloc_tos();
997         const char *conn_rootdir;
998         size_t rootdir_len;
999         char *dir_name = NULL;
1000         char *resolved_name = NULL;
1001         const char *last_component = NULL;
1002         struct smb_filename *resolved_fname = NULL;
1003         struct smb_filename *saved_dir_fname = NULL;
1004         struct smb_filename *smb_fname_cwd = NULL;
1005         struct privilege_paths *priv_paths = NULL;
1006         int ret;
1007
1008         DEBUG(3,("check_reduced_name_with_privilege [%s] [%s]\n",
1009                         smb_fname->base_name,
1010                         conn->connectpath));
1011
1012
1013         priv_paths = talloc_zero(smbreq, struct privilege_paths);
1014         if (!priv_paths) {
1015                 status = NT_STATUS_NO_MEMORY;
1016                 goto err;
1017         }
1018
1019         if (!parent_dirname(ctx, smb_fname->base_name,
1020                         &dir_name, &last_component)) {
1021                 status = NT_STATUS_NO_MEMORY;
1022                 goto err;
1023         }
1024
1025         priv_paths->parent_name.base_name = talloc_strdup(priv_paths, dir_name);
1026         priv_paths->file_name.base_name = talloc_strdup(priv_paths, last_component);
1027
1028         if (priv_paths->parent_name.base_name == NULL ||
1029                         priv_paths->file_name.base_name == NULL) {
1030                 status = NT_STATUS_NO_MEMORY;
1031                 goto err;
1032         }
1033
1034         if (SMB_VFS_STAT(conn, &priv_paths->parent_name) != 0) {
1035                 status = map_nt_error_from_unix(errno);
1036                 goto err;
1037         }
1038         /* Remember where we were. */
1039         saved_dir_fname = vfs_GetWd(ctx, conn);
1040         if (!saved_dir_fname) {
1041                 status = map_nt_error_from_unix(errno);
1042                 goto err;
1043         }
1044
1045         if (vfs_ChDir(conn, &priv_paths->parent_name) == -1) {
1046                 status = map_nt_error_from_unix(errno);
1047                 goto err;
1048         }
1049
1050         smb_fname_cwd = synthetic_smb_fname(talloc_tos(), ".", NULL, NULL, 0);
1051         if (smb_fname_cwd == NULL) {
1052                 status = NT_STATUS_NO_MEMORY;
1053                 goto err;
1054         }
1055
1056         /* Get the absolute path of the parent directory. */
1057         resolved_fname = SMB_VFS_REALPATH(conn, ctx, smb_fname_cwd);
1058         if (resolved_fname == NULL) {
1059                 status = map_nt_error_from_unix(errno);
1060                 goto err;
1061         }
1062         resolved_name = resolved_fname->base_name;
1063
1064         if (*resolved_name != '/') {
1065                 DEBUG(0,("check_reduced_name_with_privilege: realpath "
1066                         "doesn't return absolute paths !\n"));
1067                 status = NT_STATUS_OBJECT_NAME_INVALID;
1068                 goto err;
1069         }
1070
1071         DEBUG(10,("check_reduced_name_with_privilege: realpath [%s] -> [%s]\n",
1072                 priv_paths->parent_name.base_name,
1073                 resolved_name));
1074
1075         /* Now check the stat value is the same. */
1076         if (SMB_VFS_LSTAT(conn, smb_fname_cwd) != 0) {
1077                 status = map_nt_error_from_unix(errno);
1078                 goto err;
1079         }
1080
1081         /* Ensure we're pointing at the same place. */
1082         if (!check_same_stat(&smb_fname_cwd->st, &priv_paths->parent_name.st)) {
1083                 DEBUG(0,("check_reduced_name_with_privilege: "
1084                         "device/inode/uid/gid on directory %s changed. "
1085                         "Denying access !\n",
1086                         priv_paths->parent_name.base_name));
1087                 status = NT_STATUS_ACCESS_DENIED;
1088                 goto err;
1089         }
1090
1091         /* Ensure we're below the connect path. */
1092
1093         conn_rootdir = SMB_VFS_CONNECTPATH(conn, smb_fname);
1094         if (conn_rootdir == NULL) {
1095                 DEBUG(2, ("check_reduced_name_with_privilege: Could not get "
1096                         "conn_rootdir\n"));
1097                 status = NT_STATUS_ACCESS_DENIED;
1098                 goto err;
1099         }
1100
1101         rootdir_len = strlen(conn_rootdir);
1102
1103         /*
1104          * In the case of rootdir_len == 1, we know that conn_rootdir is
1105          * "/", and we also know that resolved_name starts with a slash.
1106          * So, in this corner case, resolved_name is automatically a
1107          * sub-directory of the conn_rootdir. Thus we can skip the string
1108          * comparison and the next character checks (which are even
1109          * wrong in this case).
1110          */
1111         if (rootdir_len != 1) {
1112                 bool matched;
1113
1114                 matched = (strncmp(conn_rootdir, resolved_name,
1115                                 rootdir_len) == 0);
1116
1117                 if (!matched || (resolved_name[rootdir_len] != '/' &&
1118                                  resolved_name[rootdir_len] != '\0')) {
1119                         DEBUG(2, ("check_reduced_name_with_privilege: Bad "
1120                                 "access attempt: %s is a symlink outside the "
1121                                 "share path\n",
1122                                 dir_name));
1123                         DEBUGADD(2, ("conn_rootdir =%s\n", conn_rootdir));
1124                         DEBUGADD(2, ("resolved_name=%s\n", resolved_name));
1125                         status = NT_STATUS_ACCESS_DENIED;
1126                         goto err;
1127                 }
1128         }
1129
1130         /* Now ensure that the last component either doesn't
1131            exist, or is *NOT* a symlink. */
1132
1133         ret = SMB_VFS_LSTAT(conn, &priv_paths->file_name);
1134         if (ret == -1) {
1135                 /* Errno must be ENOENT for this be ok. */
1136                 if (errno != ENOENT) {
1137                         status = map_nt_error_from_unix(errno);
1138                         DEBUG(2, ("check_reduced_name_with_privilege: "
1139                                 "LSTAT on %s failed with %s\n",
1140                                 priv_paths->file_name.base_name,
1141                                 nt_errstr(status)));
1142                         goto err;
1143                 }
1144         }
1145
1146         if (VALID_STAT(priv_paths->file_name.st) &&
1147                         S_ISLNK(priv_paths->file_name.st.st_ex_mode)) {
1148                 DEBUG(2, ("check_reduced_name_with_privilege: "
1149                         "Last component %s is a symlink. Denying"
1150                         "access.\n",
1151                         priv_paths->file_name.base_name));
1152                 status = NT_STATUS_ACCESS_DENIED;
1153                 goto err;
1154         }
1155
1156         smbreq->priv_paths = priv_paths;
1157         status = NT_STATUS_OK;
1158
1159   err:
1160
1161         if (saved_dir_fname != NULL) {
1162                 vfs_ChDir(conn, saved_dir_fname);
1163                 TALLOC_FREE(saved_dir_fname);
1164         }
1165         TALLOC_FREE(resolved_fname);
1166         if (!NT_STATUS_IS_OK(status)) {
1167                 TALLOC_FREE(priv_paths);
1168         }
1169         TALLOC_FREE(dir_name);
1170         return status;
1171 }
1172
1173 /*******************************************************************
1174  Reduce a file name, removing .. elements and checking that
1175  it is below dir in the heirachy. This uses realpath.
1176
1177  If cwd_name == NULL then fname is a client given path relative
1178  to the root path of the share.
1179
1180  If cwd_name != NULL then fname is a client given path relative
1181  to cwd_name. cwd_name is relative to the root path of the share.
1182 ********************************************************************/
1183
1184 NTSTATUS check_reduced_name(connection_struct *conn,
1185                                 const struct smb_filename *cwd_fname,
1186                                 const struct smb_filename *smb_fname)
1187 {
1188         TALLOC_CTX *ctx = talloc_tos();
1189         const char *cwd_name = cwd_fname ? cwd_fname->base_name : NULL;
1190         const char *fname = smb_fname->base_name;
1191         struct smb_filename *resolved_fname;
1192         char *resolved_name = NULL;
1193         char *new_fname = NULL;
1194         bool allow_symlinks = true;
1195         bool allow_widelinks = false;
1196
1197         DBG_DEBUG("check_reduced_name [%s] [%s]\n", fname, conn->connectpath);
1198
1199         resolved_fname = SMB_VFS_REALPATH(conn, ctx, smb_fname);
1200
1201         if (resolved_fname == NULL) {
1202                 switch (errno) {
1203                         case ENOTDIR:
1204                                 DEBUG(3,("check_reduced_name: Component not a "
1205                                          "directory in getting realpath for "
1206                                          "%s\n", fname));
1207                                 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1208                         case ENOENT:
1209                         {
1210                                 char *dir_name = NULL;
1211                                 struct smb_filename dir_fname = {0};
1212                                 const char *last_component = NULL;
1213
1214                                 /* Last component didn't exist.
1215                                    Remove it and try and canonicalise
1216                                    the directory name. */
1217                                 if (!parent_dirname(ctx, fname,
1218                                                 &dir_name,
1219                                                 &last_component)) {
1220                                         return NT_STATUS_NO_MEMORY;
1221                                 }
1222
1223                                 dir_fname = (struct smb_filename)
1224                                         { .base_name = dir_name };
1225                                 resolved_fname = SMB_VFS_REALPATH(conn,
1226                                                         ctx,
1227                                                         &dir_fname);
1228                                 if (resolved_fname == NULL) {
1229                                         NTSTATUS status = map_nt_error_from_unix(errno);
1230
1231                                         if (errno == ENOENT || errno == ENOTDIR) {
1232                                                 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1233                                         }
1234
1235                                         DEBUG(3,("check_reduce_name: "
1236                                                  "couldn't get realpath for "
1237                                                  "%s (%s)\n",
1238                                                 fname,
1239                                                 nt_errstr(status)));
1240                                         return status;
1241                                 }
1242                                 resolved_name = talloc_asprintf(ctx,
1243                                                 "%s/%s",
1244                                                 resolved_fname->base_name,
1245                                                 last_component);
1246                                 if (resolved_name == NULL) {
1247                                         return NT_STATUS_NO_MEMORY;
1248                                 }
1249                                 break;
1250                         }
1251                         default:
1252                                 DEBUG(3,("check_reduced_name: couldn't get "
1253                                          "realpath for %s\n", fname));
1254                                 return map_nt_error_from_unix(errno);
1255                 }
1256         } else {
1257                 resolved_name = resolved_fname->base_name;
1258         }
1259
1260         DEBUG(10,("check_reduced_name realpath [%s] -> [%s]\n", fname,
1261                   resolved_name));
1262
1263         if (*resolved_name != '/') {
1264                 DEBUG(0,("check_reduced_name: realpath doesn't return "
1265                          "absolute paths !\n"));
1266                 TALLOC_FREE(resolved_fname);
1267                 return NT_STATUS_OBJECT_NAME_INVALID;
1268         }
1269
1270         allow_widelinks = lp_widelinks(SNUM(conn));
1271         allow_symlinks = lp_follow_symlinks(SNUM(conn));
1272
1273         /* Common widelinks and symlinks checks. */
1274         if (!allow_widelinks || !allow_symlinks) {
1275                 const char *conn_rootdir;
1276                 size_t rootdir_len;
1277
1278                 conn_rootdir = SMB_VFS_CONNECTPATH(conn, smb_fname);
1279                 if (conn_rootdir == NULL) {
1280                         DEBUG(2, ("check_reduced_name: Could not get "
1281                                 "conn_rootdir\n"));
1282                         TALLOC_FREE(resolved_fname);
1283                         return NT_STATUS_ACCESS_DENIED;
1284                 }
1285
1286                 rootdir_len = strlen(conn_rootdir);
1287
1288                 /*
1289                  * In the case of rootdir_len == 1, we know that
1290                  * conn_rootdir is "/", and we also know that
1291                  * resolved_name starts with a slash.  So, in this
1292                  * corner case, resolved_name is automatically a
1293                  * sub-directory of the conn_rootdir. Thus we can skip
1294                  * the string comparison and the next character checks
1295                  * (which are even wrong in this case).
1296                  */
1297                 if (rootdir_len != 1) {
1298                         bool matched;
1299
1300                         matched = (strncmp(conn_rootdir, resolved_name,
1301                                         rootdir_len) == 0);
1302                         if (!matched || (resolved_name[rootdir_len] != '/' &&
1303                                          resolved_name[rootdir_len] != '\0')) {
1304                                 DEBUG(2, ("check_reduced_name: Bad access "
1305                                         "attempt: %s is a symlink outside the "
1306                                         "share path\n", fname));
1307                                 DEBUGADD(2, ("conn_rootdir =%s\n",
1308                                              conn_rootdir));
1309                                 DEBUGADD(2, ("resolved_name=%s\n",
1310                                              resolved_name));
1311                                 TALLOC_FREE(resolved_fname);
1312                                 return NT_STATUS_ACCESS_DENIED;
1313                         }
1314                 }
1315
1316                 /* Extra checks if all symlinks are disallowed. */
1317                 if (!allow_symlinks) {
1318                         /* fname can't have changed in resolved_path. */
1319                         const char *p = &resolved_name[rootdir_len];
1320
1321                         /*
1322                          * UNIX filesystem semantics, names consisting
1323                          * only of "." or ".." CANNOT be symlinks.
1324                          */
1325                         if (ISDOT(fname) || ISDOTDOT(fname)) {
1326                                 goto out;
1327                         }
1328
1329                         if (*p != '/') {
1330                                 DEBUG(2, ("check_reduced_name: logic error (%c) "
1331                                         "in resolved_name: %s\n",
1332                                         *p,
1333                                         fname));
1334                                 TALLOC_FREE(resolved_fname);
1335                                 return NT_STATUS_ACCESS_DENIED;
1336                         }
1337
1338                         p++;
1339
1340                         /*
1341                          * If cwd_name is present and not ".",
1342                          * then fname is relative to that, not
1343                          * the root of the share. Make sure the
1344                          * path we check is the one the client
1345                          * sent (cwd_name+fname).
1346                          */
1347                         if (cwd_name != NULL && !ISDOT(cwd_name)) {
1348                                 new_fname = talloc_asprintf(ctx,
1349                                                         "%s/%s",
1350                                                         cwd_name,
1351                                                         fname);
1352                                 if (new_fname == NULL) {
1353                                         TALLOC_FREE(resolved_fname);
1354                                         return NT_STATUS_NO_MEMORY;
1355                                 }
1356                                 fname = new_fname;
1357                         }
1358
1359                         if (strcmp(fname, p)!=0) {
1360                                 DEBUG(2, ("check_reduced_name: Bad access "
1361                                         "attempt: %s is a symlink to %s\n",
1362                                           fname, p));
1363                                 TALLOC_FREE(resolved_fname);
1364                                 TALLOC_FREE(new_fname);
1365                                 return NT_STATUS_ACCESS_DENIED;
1366                         }
1367                 }
1368         }
1369
1370   out:
1371
1372         DBG_INFO("%s reduced to %s\n", fname, resolved_name);
1373         TALLOC_FREE(resolved_fname);
1374         TALLOC_FREE(new_fname);
1375         return NT_STATUS_OK;
1376 }
1377
1378 /**
1379  * XXX: This is temporary and there should be no callers of this once
1380  * smb_filename is plumbed through all path based operations.
1381  *
1382  * Called when we know stream name parsing has already been done.
1383  */
1384 int vfs_stat_smb_basename(struct connection_struct *conn,
1385                         const struct smb_filename *smb_fname_in,
1386                         SMB_STRUCT_STAT *psbuf)
1387 {
1388         struct smb_filename smb_fname = {
1389                 .base_name = discard_const_p(char, smb_fname_in->base_name),
1390                 .flags = smb_fname_in->flags
1391         };
1392         int ret;
1393
1394         if (smb_fname.flags & SMB_FILENAME_POSIX_PATH) {
1395                 ret = SMB_VFS_LSTAT(conn, &smb_fname);
1396         } else {
1397                 ret = SMB_VFS_STAT(conn, &smb_fname);
1398         }
1399
1400         if (ret != -1) {
1401                 *psbuf = smb_fname.st;
1402         }
1403         return ret;
1404 }
1405
1406 /**
1407  * Ensure LSTAT is called for POSIX paths.
1408  */
1409
1410 NTSTATUS vfs_stat_fsp(files_struct *fsp)
1411 {
1412         int ret;
1413
1414         if(fsp->fh->fd == -1) {
1415                 if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) {
1416                         ret = SMB_VFS_LSTAT(fsp->conn, fsp->fsp_name);
1417                 } else {
1418                         ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name);
1419                 }
1420                 if (ret == -1) {
1421                         return map_nt_error_from_unix(errno);
1422                 }
1423         } else {
1424                 if(SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st) != 0) {
1425                         return map_nt_error_from_unix(errno);
1426                 }
1427         }
1428         return NT_STATUS_OK;
1429 }
1430
1431 /**
1432  * Initialize num_streams and streams, then call VFS op streaminfo
1433  */
1434 NTSTATUS vfs_streaminfo(connection_struct *conn,
1435                         struct files_struct *fsp,
1436                         const struct smb_filename *smb_fname,
1437                         TALLOC_CTX *mem_ctx,
1438                         unsigned int *num_streams,
1439                         struct stream_struct **streams)
1440 {
1441         *num_streams = 0;
1442         *streams = NULL;
1443         return SMB_VFS_STREAMINFO(conn,
1444                         fsp,
1445                         smb_fname,
1446                         mem_ctx,
1447                         num_streams,
1448                         streams);
1449 }
1450
1451 /*
1452   generate a file_id from a stat structure
1453  */
1454 struct file_id vfs_file_id_from_sbuf(connection_struct *conn, const SMB_STRUCT_STAT *sbuf)
1455 {
1456         return SMB_VFS_FILE_ID_CREATE(conn, sbuf);
1457 }
1458
1459 /*
1460  * Design of the smb_vfs_ev_glue infrastructure:
1461  *
1462  * smb_vfs_ev_glue makes it possible to pass
1463  * down an tevent_context and pthreadpool_tevent
1464  * used for impersonation through the SMB_VFS stack.
1465  *
1466  * tevent_req based function take an tevent_context as
1467  * there 2nd argument, e.g.:
1468  *
1469  *   struct tevent_req *something_send(TALLOC_CTX *mem_ctx,
1470  *                                     struct tevent_context *ev,
1471  *                                     ...);
1472  *
1473  * For the SMB_VFS stack we'll use the following:
1474  *
1475  *   struct tevent_req *SMB_VFS_SOMETHING_SEND(TALLOC_CTX *mem_ctx,
1476  *                                             const struct smb_vfs_ev_glue *evg,
1477  *                                             ...);
1478  *
1479  * Typically the 'evg' is just passed through the stack down
1480  * to vfs_default.c. In order to do real work an
1481  * tevent_context and pthreadpool_tevent are required
1482  * to do call a 'somthing()' syscall in an async fashion.
1483  * Therefore it will the following to get the pointer
1484  * back out of evg:
1485  *
1486  *   ev = smb_vfs_ev_glue_ev_ctx(evg);
1487  *   tp = smb_vfs_ev_glue_tp_chdir_safe(evg);
1488  *
1489  * If some function in the stack is sure it needs to run as root
1490  * to get some information (after careful checks!), it used
1491  * to frame that work into become_root()/unbecome_root().
1492  * This can't work when using async functions!
1493  * Now it's possible to use something like this (simplified!):
1494  *
1495  *   ev = smb_vfs_ev_glue_ev_ctx(evg);
1496  *   root_evg = smb_vfs_ev_glue_get_root_glue(evg);
1497  *   subreq = SMB_VFS_SOMETHING_NEXT_SEND(state, root_evg, ...);
1498  *   if (tevent_req_nomem(subreq, req)) {
1499  *        return tevent_req_post(req, ev);
1500  *   }
1501  *   tevent_req_set_callback(subreq, module_something_done, req);
1502  *
1503  *   return req;
1504  *
1505  *   static void module_something_done(struct tevent_req *subreq)
1506  *   {
1507  *      ...
1508  *
1509  *      status = SMB_VFS_SOMETHING_NEXT_RECV(subreq, &state->aio_state);
1510  *      TALLOC_FREE(subreq);
1511  *
1512  *      tevent_req_done(req);
1513  *   }
1514  *
1515  * In the code above the something_send_fn() function of the next
1516  * module in the stack will be called as root.
1517  * The smb_vfs_call_something_*() glue code, which is the magic
1518  * behind the SMB_VFS_SOMETHING[_NEXT]_{SEND,RECV}() macros,
1519  * will look like this:
1520  *
1521  *   struct smb_vfs_call_something_state {
1522  *       ssize_t (*recv_fn)(struct tevent_req *req,
1523  *                          struct vfs_aio_state *aio_state,
1524  *                          ...);
1525  *       ssize_t retval;
1526  *       struct vfs_aio_state vfs_aio_state;
1527  *       ...
1528  *   };
1529  *
1530  *   static void smb_vfs_call_something_done(struct tevent_req *subreq);
1531  *
1532  *   struct tevent_req *smb_vfs_call_something_send(
1533  *                  TALLOC_CTX *mem_ctx,
1534  *                  const struct smb_vfs_ev_glue *evg,
1535  *                  struct vfs_handle_struct *handle,
1536  *                  ...)
1537  *   {
1538  *       struct tevent_req *req = NULL;
1539  *       struct smb_vfs_call_something_state *state = NULL;
1540  *       struct tevent_req *subreq = NULL;
1541  *       bool ok;
1542  *
1543  *       req = tevent_req_create(mem_ctx, &state,
1544  *                               struct smb_vfs_call_something_state);
1545  *       if (req == NULL) {
1546  *           return NULL;
1547  *       }
1548  *
1549  *       VFS_FIND(something_send);
1550  *       state->recv_fn = handle->fns->something_recv_fn;
1551  *
1552  *       ok = smb_vfs_ev_glue_push_use(evg, req);
1553  *       if (!ok) {
1554  *           tevent_req_error(req, EIO);
1555  *           return tevent_req_post(req, evg->return_ev);
1556  *       }
1557  *
1558  *       subreq = handle->fns->something_send_fn(mem_ctx,
1559  *                                               evg->next_glue,
1560  *                                               handle,
1561  *                                               ...);
1562  *       smb_vfs_ev_glue_pop_use(evg);
1563  *
1564  *       if (tevent_req_nomem(subreq, req)) {
1565  *           return tevent_req_post(req, evg->return_ev);
1566  *       }
1567  *       tevent_req_set_callback(subreq, smb_vfs_call_something_done, req);
1568  *
1569  *       return req;
1570  *   }
1571  *
1572  *   static void smb_vfs_call_something_done(struct tevent_req *subreq)
1573  *   {
1574  *       struct tevent_req *req =
1575  *           tevent_req_callback_data(subreq,
1576  *           struct tevent_req);
1577  *       struct smb_vfs_call_something_state *state =
1578  *           tevent_req_data(req,
1579  *           struct smb_vfs_call_something_state);
1580  *
1581  *       state->retval = state->recv_fn(subreq,
1582  *                                      &state->vfs_aio_state,
1583  *                                      ....);
1584  *       TALLOC_FREE(subreq);
1585  *
1586  *       if (state->retval == -1) {
1587  *           tevent_req_error(req, state->vfs_aio_state.error);
1588  *           return;
1589  *       }
1590  *       tevent_req_done(req);
1591  *   }
1592  *
1593  *   ssize_t smb_vfs_call_something_recv(struct tevent_req *req,
1594  *                                        struct vfs_aio_state *aio_state,
1595  *                                        ....)
1596  *   {
1597  *       struct smb_vfs_call_something_state *state =
1598  *           tevent_req_data(req,
1599  *           struct smb_vfs_call_something_state);
1600  *       ssize_t retval = state->retval;
1601  *
1602  *       if (tevent_req_is_unix_error(req, &aio_state->error)) {
1603  *           tevent_req_received(req);
1604  *           return -1;
1605  *       }
1606  *
1607  *       *aio_state = state->vfs_aio_state;
1608  *       ...
1609  *
1610  *       tevent_req_received(req);
1611  *       return retval;
1612  *   }
1613  *
1614  * The most important details are these:
1615  *
1616  * 1. smb_vfs_ev_glue_push_use(evg, req):
1617  *    - is a no-op if evg->run_ev and evg->return_ev are the same,
1618  *      it means that we're already at the correct impersonation
1619  *      and don't need any additional work to be done.
1620  *    - Otherwise it will call tevent_req_defer_callback(req, evg->return_ev)
1621  *      This means that tevent_req_error() and tevent_req_done()
1622  *      will just trigger an immediate event on evg->return_ev.
1623  *      Therefore the callers callback function will be called
1624  *      in the impersonation of evg->return_ev! This is important
1625  *      in order to get the impersonation correct on the way back
1626  *      through the stack.
1627  *    - It will call tevent_context_push_use(evg->run_ev),
1628  *      which will start the impersonation to run_ev.
1629  *      So the following code run in the correct context.
1630  * 2. handle->fns->something_send_fn(..., evg->next_glue, ...):
1631  *    - We're passing evg->next_glue to the next module.
1632  *    - Typically evg->next_glue points to evg again.
1633  *    - In case evg->run_ev and evg->return_ev are not the same,
1634  *      next_glue will have run_ev and return_ev pointing to evg->run_ev.
1635  *      So that the switch from evg->run_ev to evg->return_ev
1636  *      happens on the correct boundary.
1637  * 3. smb_vfs_ev_glue_pop_use(evg):
1638  *    - is a no-op if evg->run_ev and evg->return_ev are the same,
1639  *      it means that we're already at the correct impersonation
1640  *      and don't need any additional work to be done.
1641  *    - It will call tevent_context_pop_use(evg->run_ev),
1642  *      which will revert the impersonation done in
1643  *      smb_vfs_ev_glue_push_use().
1644  * 4. smb_vfs_call_something_send():
1645  *    - The is called in the environment of evg->return_ev.
1646  *    - So it needs to use tevent_req_post(req, evg->return_ev)
1647  * 5. smb_vfs_call_something_done():
1648  *    - The is called in the environment of evg->run_ev
1649  * 6. smb_vfs_call_something_recv():
1650  *    - The is called in the environment of evg->return_ev again.
1651  *
1652  *
1653  * Here are some more complex examples:
1654  *
1655  * Example 1: only user_evg without switch to root
1656  *
1657  * SMBD: already impersonated user_evg
1658  *  evg'1 = smb2_req->user_evg
1659  *  r'1 = SMB_VFS_*_SEND(evg'1); # smb_vfs_call_*_send()
1660  *  |
1661  *  | smb_vfs_ev_glue_push_use(evg'1, r'1);
1662  *  | |
1663  *  | | # no-op run_ev == return_ev
1664  *  | |
1665  *  | evg'2 = evg'1->next_glue;
1666  *  | r'2 = module1_*_send(evg'2);
1667  *  | |
1668  *  | | evg'3 = evg'2
1669  *  | | r'3 = SMB_VFS_*_NEXT_SEND(evg'3); # smb_vfs_call_*_send()
1670  *  | | |
1671  *  | | | smb_vfs_ev_glue_push_use(evg'3, r'3);
1672  *  | | | |
1673  *  | | | | # no-op run_ev == return_ev
1674  *  | | | |
1675  *  | | | evg'4 = evg'3->next_glue;
1676  *  | | | r'4 = module2_*_send(evg'4);
1677  *  | | | |
1678  *  | | | | evg'5 = evg'4
1679  *  | | | | r'5 = SMB_VFS_*_NEXT_SEND(evg'5); # smb_vfs_call_*_send()
1680  *  | | | | |
1681  *  | | | | | smb_vfs_ev_glue_push_use(evg'5, r'5);
1682  *  | | | | | |
1683  *  | | | | | | # no-op run_ev == return_ev
1684  *  | | | | | |
1685  *  | | | | | evg'6 = evg'5->next_glue;
1686  *  | | | | | r'6 = default_*_send(evg'6);
1687  *  | | | | | |
1688  *  | | | | | | ev'6 = smb_vfs_ev_glue_ev_ctx(evg'6)
1689  *  | | | | | | tp'6 = smb_vfs_ev_glue_tp_chdir_safe(evg'6)
1690  *  | | | | | | r'7 = pthreadpool_tevent_send(ev'6, tp'6);
1691  *  | | | | | | |
1692  *  | | | | | | | pthread_create...
1693  *  | | | | | | |
1694  *  | | | | | | tevent_req_set_callback(r'7, default_*_done, r'6);
1695  *  | | | | | |
1696  *  | | | | | smb_vfs_ev_glue_pop_use(evg'5);
1697  *  | | | | | |
1698  *  | | | | | | # no-op run_ev == return_ev
1699  *  | | | | | |
1700  *  | | | | | tevent_req_set_callback(r'6, smb_vfs_call_*_done, r'5);
1701  *  | | | | |
1702  *  | | | | tevent_req_set_callback(r'5, module2_*_done, r'4);
1703  *  | | | |
1704  *  | | | smb_vfs_ev_glue_pop_use(evg'3);
1705  *  | | | |
1706  *  | | | | # no-op run_ev == return_ev
1707  *  | | | |
1708  *  | | | tevent_req_set_callback(r'4, smb_vfs_call_*_done, r'3);
1709  *  | | |
1710  *  | | tevent_req_set_callback(r'3, module1_*_done, r'2);
1711  *  | |
1712  *  | smb_vfs_ev_glue_pop_use(evg'1);
1713  *  | |
1714  *  | | # no-op run_ev == return_ev
1715  *  | |
1716  *  | tevent_req_set_callback(r'2, smb_vfs_call_*_done, r'1);
1717  *  |
1718  *  tevent_req_set_callback(r'1, smbd_*_done, smb2_req);
1719  *
1720  *  Worker thread finished, just one event handler processes
1721  *  everything as there's no impersonation change.
1722  *
1723  *  tevent_common_invoke_immediate_handler:
1724  *  |
1725  *  | before_immediate_handler(ev'6);
1726  *  | |
1727  *  | | change_to_user()
1728  *  | |
1729  *  | pthreadpool_tevent_job_done(r'7);
1730  *  | |
1731  *  | | default_*_done(r'7);
1732  *  | | |
1733  *  | | | pthreadpool_tevent_recv(r'7);
1734  *  | | | TALLOC_FREE(r'7);
1735  *  | | | tevent_req_done('r6);
1736  *  | | | |
1737  *  | | | | smb_vfs_call_*_done(r'6);
1738  *  | | | | |
1739  *  | | | | | default_*_recv(r'6);
1740  *  | | | | | TALLOC_FREE(r'6)
1741  *  | | | | | tevent_req_done(r'5);
1742  *  | | | | | |
1743  *  | | | | | | module2_*_done(r'5):
1744  *  | | | | | | |
1745  *  | | | | | | | SMB_VFS_*_recv(r'5); # smb_vfs_call_*_recv()
1746  *  | | | | | | | TALLOC_FREE(r'5)
1747  *  | | | | | | | tevent_req_done(r'4);
1748  *  | | | | | | | |
1749  *  | | | | | | | | smb_vfs_call_*_done(r'4);
1750  *  | | | | | | | | |
1751  *  | | | | | | | | | module2_*_recv(r'4);
1752  *  | | | | | | | | | TALLOC_FREE(r'4)
1753  *  | | | | | | | | | tevent_req_done(r'3);
1754  *  | | | | | | | | | |
1755  *  | | | | | | | | | | module1_*_done(r'3):
1756  *  | | | | | | | | | | |
1757  *  | | | | | | | | | | | SMB_VFS_*_recv(r'3); # smb_vfs_call_*_recv()
1758  *  | | | | | | | | | | | TALLOC_FREE(r'3)
1759  *  | | | | | | | | | | | tevent_req_done(r'2);
1760  *  | | | | | | | | | | | |
1761  *  | | | | | | | | | | | | smb_vfs_*_done(r'2);
1762  *  | | | | | | | | | | | | |
1763  *  | | | | | | | | | | | | | module1_*_recv(r'2);
1764  *  | | | | | | | | | | | | | TALLOC_FREE(r'2)
1765  *  | | | | | | | | | | | | | tevent_req_done(r'1);
1766  *  | | | | | | | | | | | | | |
1767  *  | | | | | | | | | | | | | | smbd_*_done(r'1);
1768  *  | | | | | | | | | | | | | | |
1769  *  | | | | | | | | | | | | | | | SMB_VFS_*_recv(r'1); # smb_vfs_call_*_recv()
1770  *  | | | | | | | | | | | | | | | TALLOC_FREE(r'1)
1771  *  | | | | | | | | | | | | | | | smbd_response_to_client()
1772  *  | | | | | | | | | | | | | | | return
1773  *  | | | | | | | | | | | | | | |
1774  *  | | | | | | | | | | | | | | return
1775  *  | | | | | | | | | | | | | |
1776  *  | | | | | | | | | | | | | return
1777  *  | | | | | | | | | | | | |
1778  *  | | | | | | | | | | | | return
1779  *  | | | | | | | | | | | |
1780  *  | | | | | | | | | | | return
1781  *  | | | | | | | | | | |
1782  *  | | | | | | | | | | return
1783  *  | | | | | | | | | |
1784  *  | | | | | | | | | return
1785  *  | | | | | | | | |
1786  *  | | | | | | | | return
1787  *  | | | | | | | |
1788  *  | | | | | | | return
1789  *  | | | | | | |
1790  *  | | | | | | return
1791  *  | | | | | |
1792  *  | | | | | return
1793  *  | | | | |
1794  *  | | | | return
1795  *  | | | |
1796  *  | | | return
1797  *  | | |
1798  *  | | return
1799  *  | |
1800  *  | after_immediate_handler(ev'6);
1801  *  | |
1802  *  | | # lazy no change_to_user()
1803  *  | |
1804  *  | return
1805  *
1806  *
1807  * Example 2: start with user_evg and let module1 switch to root
1808  *
1809  * SMBD: already impersonated user_evg
1810  *  evg'1 = smb2_req->user_evg
1811  *  r'1 = SMB_VFS_*_SEND(evg'1); # smb_vfs_call_*_send()
1812  *  |
1813  *  | smb_vfs_ev_glue_push_use(evg'1, r'1);
1814  *  | |
1815  *  | | # no-op run_ev == return_ev
1816  *  | |
1817  *  | evg'2 = evg'1->next_glue;
1818  *  | r'2 = module1_*_send(evg'2);
1819  *  | |
1820  *  | | evg'3 = smb_vfs_ev_glue_get_root_glue(evg'2)
1821  *  | | r'3 = SMB_VFS_*_NEXT_SEND(evg'3); # smb_vfs_call_*_send()
1822  *  | | |
1823  *  | | | smb_vfs_ev_glue_push_use(evg'3, r'3);
1824  *  | | | |
1825  *  | | | | tevent_req_defer_callback(r'3, evg'3->return_ev);
1826  *  | | | | tevent_context_push_use(evg'3->run_ev)
1827  *  | | | | |
1828  *  | | | | | become_root()
1829  *  | | | | |
1830  *  | | | |
1831  *  | | | evg'4 = evg'3->next_glue;
1832  *  | | | r'4 = module2_*_send(evg'4);
1833  *  | | | |
1834  *  | | | | evg'5 = smb_vfs_ev_glue_get_root_glue(evg'4)
1835  *  | | | | r'5 = SMB_VFS_*_NEXT_SEND(evg'5); # smb_vfs_call_*_send()
1836  *  | | | | |
1837  *  | | | | | smb_vfs_ev_glue_push_use(evg'5, r'5);
1838  *  | | | | | |
1839  *  | | | | | | # no-op run_ev == return_ev, already root
1840  *  | | | | | |
1841  *  | | | | | evg'6 = evg'5->next_glue;
1842  *  | | | | | r'6 = default_*_send(evg'6);
1843  *  | | | | | |
1844  *  | | | | | | ev'6 = smb_vfs_ev_glue_ev_ctx(evg'6)
1845  *  | | | | | | tp'6 = smb_vfs_ev_glue_tp_chdir_safe(evg'6)
1846  *  | | | | | | r'7 = pthreadpool_tevent_send(ev'6, tp'6);
1847  *  | | | | | | |
1848  *  | | | | | | | pthread_create...
1849  *  | | | | | | |
1850  *  | | | | | | tevent_req_set_callback(r'7, default_*_done, r'6);
1851  *  | | | | | |
1852  *  | | | | | smb_vfs_ev_glue_pop_use(evg'5);
1853  *  | | | | | |
1854  *  | | | | | | # no-op run_ev == return_ev, still stay as root
1855  *  | | | | | |
1856  *  | | | | | tevent_req_set_callback(r'6, smb_vfs_*_done, r'5);
1857  *  | | | | |
1858  *  | | | | tevent_req_set_callback(r'5, module2_*_done, r'4);
1859  *  | | | |
1860  *  | | | smb_vfs_ev_glue_pop_use(evg'3);
1861  *  | | | |
1862  *  | | | | tevent_context_pop_use(evg'3->run_ev)
1863  *  | | | | |
1864  *  | | | | | unbecome_root()
1865  *  | | | |
1866  *  | | | tevent_req_set_callback(r'4, smb_vfs_*_done, r'3);
1867  *  | | |
1868  *  | | tevent_req_set_callback(r'3, module1_*_done, r'2);
1869  *  | |
1870  *  | smb_vfs_ev_glue_pop_use(evg'1);
1871  *  | |
1872  *  | | # no-op run_ev == return_ev
1873  *  | |
1874  *  | tevent_req_set_callback(r'2, smb_vfs_*_done, r'1);
1875  *  |
1876  *  tevent_req_set_callback(r'1, smbd_*_done, smb2_req);
1877  *
1878  *  Worker thread finished, just one event handler processes
1879  *  everything as there's no impersonation change.
1880  *
1881  *  tevent_common_invoke_immediate_handler:
1882  *  |
1883  *  | before_immediate_handler(ev'6);
1884  *  | |
1885  *  | | become_root()
1886  *  | |
1887  *  | pthreadpool_tevent_job_done(r'7);
1888  *  | |
1889  *  | | default_*_done(r'7);
1890  *  | | |
1891  *  | | | pthreadpool_tevent_recv(r'7);
1892  *  | | | TALLOC_FREE(r'7);
1893  *  | | | tevent_req_done('r6);
1894  *  | | | |
1895  *  | | | | smb_vfs_*_done(r'6);
1896  *  | | | | |
1897  *  | | | | | default_*_recv(r'6);
1898  *  | | | | | TALLOC_FREE(r'6)
1899  *  | | | | | tevent_req_done(r'5);
1900  *  | | | | | |
1901  *  | | | | | | module2_*_done(r'5):
1902  *  | | | | | | |
1903  *  | | | | | | | SMB_VFS_*_recv(r'5);
1904  *  | | | | | | | TALLOC_FREE(r'5)
1905  *  | | | | | | | tevent_req_done(r'4);
1906  *  | | | | | | | |
1907  *  | | | | | | | | smb_vfs_*_done(r'4);
1908  *  | | | | | | | | |
1909  *  | | | | | | | | | module2_*_recv(r'4);
1910  *  | | | | | | | | | TALLOC_FREE(r'4)
1911  *  | | | | | | | | | tevent_req_done(r'3);
1912  *  | | | | | | | | | | return
1913  *  | | | | | | | | | |
1914  *  | | | | | | | | | return
1915  *  | | | | | | | | |
1916  *  | | | | | | | | return
1917  *  | | | | | | | |
1918  *  | | | | | | | return
1919  *  | | | | | | |
1920  *  | | | | | | return
1921  *  | | | | | |
1922  *  | | | | | return
1923  *  | | | | |
1924  *  | | | | return
1925  *  | | | |
1926  *  | | | return
1927  *  | | |
1928  *  | | return
1929  *  | |
1930  *  | |
1931  *  | after_immediate_handler(ev'6);
1932  *  | |
1933  *  | | unbecome_root()
1934  *  | |
1935  *  | return
1936  *  |
1937  *  tevent_common_invoke_immediate_handler:
1938  *  |
1939  *  | before_immediate_handler(ev'6);
1940  *  | |
1941  *  | | change_to_user()
1942  *  | |
1943  *  | tevent_req_trigger();
1944  *  | ...
1945  *  | _tevent_req_notify_callback(r'3)
1946  *  | |
1947  *  | | module1_*_done(r'3):
1948  *  | | |
1949  *  | | | SMB_VFS_*_recv(r'3);
1950  *  | | | TALLOC_FREE(r'3)
1951  *  | | | tevent_req_done(r'2);
1952  *  | | | |
1953  *  | | | | smb_vfs_*_done(r'2);
1954  *  | | | | |
1955  *  | | | | | module1_*_recv(r'2);
1956  *  | | | | | TALLOC_FREE(r'2)
1957  *  | | | | | tevent_req_done(r'1);
1958  *  | | | | | |
1959  *  | | | | | | smbd_*_done(r'1);
1960  *  | | | | | | |
1961  *  | | | | | | | SMB_VFS_*_recv(r'1);
1962  *  | | | | | | | TALLOC_FREE(r'1)
1963  *  | | | | | | | smbd_response_to_client()
1964  *  | | | | | | | return
1965  *  | | | | | | |
1966  *  | | | | | | return
1967  *  | | | | | |
1968  *  | | | | | return
1969  *  | | | | |
1970  *  | | | | return
1971  *  | | | |
1972  *  | | | return
1973  *  | | |
1974  *  | | return
1975  *  | |
1976  *  | after_immediate_handler(ev'6);
1977  *  | |
1978  *  | | # lazy no change_to_user()
1979  *  | |
1980  *  | return
1981  *
1982  */
1983 struct smb_vfs_ev_glue {
1984         /*
1985          * The event context that should be used
1986          * to report the result back.
1987          *
1988          * The is basically the callers context.
1989          */
1990         struct tevent_context *return_ev;
1991
1992         /*
1993          * The event context and threadpool wrappers
1994          * the current context should use.
1995          *
1996          * tp_fd_safe only allows fd based functions
1997          * which don't require impersonation, this
1998          * is basically the raw threadpool.
1999          *
2000          * tp_path_safe allows path based functions
2001          * to be called under the correct impersonation.
2002          * But chdir/fchdir is not allowed!
2003          * Typically calls like openat() or other *at()
2004          * syscalls.
2005          *
2006          * tp_chdir_safe is like path_safe, but also
2007          * allows chdir/fchdir to be called, the job
2008          * can safely return with a changed directory,
2009          * the threadpool wrapper takes care of
2010          * a cleanup if required.
2011          * This is needed if *at() syscalls need
2012          * to be simulated by fchdir();$syscall(),
2013          * e.g. getxattr().
2014          *
2015          * The distinction between these threadpool
2016          * is required because of OS limitations
2017          * (as of 2018):
2018          * - only Linux supports per thread
2019          *   credentials (seteuid....)
2020          * - only Linux supports a per thread
2021          *   current working directory,
2022          *   using unshare(CLONE_FS). But
2023          *   in some constrained container
2024          *   environments even that is not available
2025          *   on Linux.
2026          *
2027          * tp_fd_safe is typically the raw threadpool
2028          * without a wrapper.
2029          *
2030          * On Linux tp_path_safe and tp_chdir_safe
2031          * are typically the same (if unshare(CLONE_FS) is available)
2032          * they're implemented as wrappers of the raw threadpool.
2033          *
2034          * On other OSes tp_path_safe is a wrapper
2035          * arround a sync threadpool (without real threads, just blocking
2036          * the main thread), but hidden behind the pthreadpool_tevent
2037          * api in order to make the restriction transparent.
2038          *
2039          * On other OSes tp_chdir_safe is a wrapper
2040          * arround a sync threadpool (without real threads, just blocking
2041          * the main thread), but hidden behind the pthreadpool_tevent
2042          * api in order to make the restriction transparent.
2043          * It just remembers/restores the current working directory,
2044          * typically using open(".", O_RDONLY | O_DIRECTORY) and fchdir().
2045          */
2046         struct tevent_context *run_ev;
2047         struct pthreadpool_tevent *run_tp_fd_safe;
2048         struct pthreadpool_tevent *run_tp_path_safe;
2049         struct pthreadpool_tevent *run_tp_chdir_safe;
2050
2051         /*
2052          * The glue that should be passed down
2053          * to sub request in the stack.
2054          *
2055          * Typically this points to itself.
2056          *
2057          * But smb_vfs_ev_glue_create_switch() allows
2058          * to create context that can switch
2059          * between two user glues.
2060          */
2061         const struct smb_vfs_ev_glue *next_glue;
2062
2063         /*
2064          * If some code path wants to run
2065          * some constraint code as root,
2066          * basically an async version of become_root()
2067          * and unbecome_root().
2068          *
2069          * The caller can call smb_vfs_ev_glue_get_root_glue()
2070          * to get a root glue that can be passed
2071          * to the SMB_VFS_*_SEND() function that
2072          * should run as root.
2073          *
2074          * Note that the callback (registered with
2075          * tevent_req_set_callback()) won't run as
2076          * root anymore!
2077          */
2078         const struct smb_vfs_ev_glue *root_glue;
2079 };
2080
2081 static struct smb_vfs_ev_glue *smb_vfs_ev_glue_create_internal(
2082         TALLOC_CTX *mem_ctx,
2083         struct tevent_context *return_ev,
2084         struct tevent_context *run_ev,
2085         struct pthreadpool_tevent *run_tp_fd_safe,
2086         struct pthreadpool_tevent *run_tp_path_safe,
2087         struct pthreadpool_tevent *run_tp_chdir_safe)
2088 {
2089         struct smb_vfs_ev_glue *evg = NULL;
2090
2091         evg = talloc_zero(mem_ctx, struct smb_vfs_ev_glue);
2092         if (evg == NULL) {
2093                 return NULL;
2094         }
2095         *evg = (struct smb_vfs_ev_glue) {
2096                 .return_ev = return_ev,
2097                 .run_ev = run_ev,
2098                 .run_tp_fd_safe = run_tp_fd_safe,
2099                 .run_tp_path_safe = run_tp_path_safe,
2100                 .run_tp_chdir_safe = run_tp_chdir_safe,
2101                 .next_glue = evg,
2102         };
2103
2104         return evg;
2105 }
2106
2107 struct tevent_context *smb_vfs_ev_glue_ev_ctx(const struct smb_vfs_ev_glue *evg)
2108 {
2109         return evg->run_ev;
2110 }
2111
2112 struct pthreadpool_tevent *smb_vfs_ev_glue_tp_fd_safe(const struct smb_vfs_ev_glue *evg)
2113 {
2114         return evg->run_tp_fd_safe;
2115 }
2116
2117 struct pthreadpool_tevent *smb_vfs_ev_glue_tp_path_safe(const struct smb_vfs_ev_glue *evg)
2118 {
2119         return evg->run_tp_path_safe;
2120 }
2121
2122 struct pthreadpool_tevent *smb_vfs_ev_glue_tp_chdir_safe(const struct smb_vfs_ev_glue *evg)
2123 {
2124         return evg->run_tp_chdir_safe;
2125 }
2126
2127 const struct smb_vfs_ev_glue *smb_vfs_ev_glue_get_root_glue(const struct smb_vfs_ev_glue *evg)
2128 {
2129         return evg->root_glue;
2130 }
2131
2132 struct smb_vfs_ev_glue *smb_vfs_ev_glue_create(TALLOC_CTX *mem_ctx,
2133                                 struct tevent_context *user_ev,
2134                                 struct pthreadpool_tevent *user_tp_fd_safe,
2135                                 struct pthreadpool_tevent *user_tp_path_safe,
2136                                 struct pthreadpool_tevent *user_tp_chdir_safe,
2137                                 struct tevent_context *root_ev,
2138                                 struct pthreadpool_tevent *root_tp_fd_safe,
2139                                 struct pthreadpool_tevent *root_tp_path_safe,
2140                                 struct pthreadpool_tevent *root_tp_chdir_safe)
2141 {
2142         struct smb_vfs_ev_glue *evg_uu = NULL;
2143         struct smb_vfs_ev_glue *evg_ru = NULL;
2144         struct smb_vfs_ev_glue *evg_rr = NULL;
2145
2146         /*
2147          * The top level glue (directly returned from this function).
2148          *
2149          * It uses user_ev and user_tp_* only.
2150          */
2151         evg_uu = smb_vfs_ev_glue_create_internal(mem_ctx,
2152                                                  user_ev, /* return_ev */
2153                                                  user_ev, /* run_ev */
2154                                                  user_tp_fd_safe,
2155                                                  user_tp_path_safe,
2156                                                  user_tp_chdir_safe);
2157         if (evg_uu == NULL) {
2158                 return NULL;
2159         }
2160
2161         /*
2162          * The first root glue (returned by smb_vfs_ev_glue_get_root_glue()).
2163          *
2164          * It uses root_ev and root_tp, but user_ev as return ev,
2165          * which means that the caller's callback (registered with
2166          * tevent_req_set_callback()) will run as user_ev.
2167          */
2168         evg_ru = smb_vfs_ev_glue_create_internal(evg_uu,
2169                                                  user_ev, /* return_ev */
2170                                                  root_ev, /* run_ev */
2171                                                  root_tp_fd_safe,
2172                                                  root_tp_path_safe,
2173                                                  root_tp_chdir_safe);
2174         if (evg_ru == NULL) {
2175                 TALLOC_FREE(evg_uu);
2176                 return NULL;
2177         }
2178
2179         /*
2180          * The second root glue (returned by smb_vfs_ev_glue_get_root_glue() on
2181          * root glue itself. This means code can always call
2182          * smb_vfs_ev_glue_get_root_glue() and don't have to care if the
2183          * passed glue is already a root glue.
2184          *
2185          * This will then recursively point to its own root_glue pointer.
2186          *
2187          * It only uses root_ev and root_tp.
2188          */
2189         evg_rr = smb_vfs_ev_glue_create_internal(evg_ru,
2190                                                  root_ev, /* return_ev */
2191                                                  root_ev, /* run_ev */
2192                                                  root_tp_fd_safe,
2193                                                  root_tp_path_safe,
2194                                                  root_tp_chdir_safe);
2195         if (evg_rr == NULL) {
2196                 TALLOC_FREE(evg_uu);
2197                 return NULL;
2198         }
2199
2200         /*
2201          * We now setup the glue hierachie.
2202          *
2203          * Search for "Design of the smb_vfs_ev_glue infrastructure" above
2204          * for a detailed description how the chain works.
2205          *
2206          * "Example 2: start with user_evg and let module1 switch to root"
2207          * explains it for the root_glue chaining.
2208          */
2209         evg_rr->root_glue = evg_rr;
2210         evg_ru->root_glue = evg_rr;
2211         evg_uu->root_glue = evg_ru;
2212
2213         /*
2214          * As evg_ru is a boundary with
2215          * run_ev != return_ev, we need to
2216          * alter its next_glue.
2217          */
2218         evg_ru->next_glue = evg_rr;
2219
2220         return evg_uu;
2221 }
2222
2223 /*
2224  * This can be used to create a temporary glue
2225  * if you need to switch between two user contexts
2226  *
2227  * It's the caller's duty to make sure both
2228  * glues stay alive for the lifetime of the
2229  * created switch.
2230  */
2231 struct smb_vfs_ev_glue *smb_vfs_ev_glue_create_switch(
2232                         TALLOC_CTX *mem_ctx,
2233                         const struct smb_vfs_ev_glue *return_evg,
2234                         const struct smb_vfs_ev_glue *run_evg)
2235 {
2236         const struct smb_vfs_ev_glue *run_root = run_evg->root_glue;
2237         struct smb_vfs_ev_glue *evg_u = NULL;
2238         struct smb_vfs_ev_glue *evg_r = NULL;
2239
2240         /*
2241          * Here we basically need to dup run_evg (and run_evg->root_glue)
2242          * and replace their return_ev with return_evg->return_ev.
2243          *
2244          * We need to put the new evgs in front of the chain...
2245          */
2246         evg_u = smb_vfs_ev_glue_create_internal(mem_ctx,
2247                                                 return_evg->return_ev,
2248                                                 run_evg->run_ev,
2249                                                 run_evg->run_tp_fd_safe,
2250                                                 run_evg->run_tp_path_safe,
2251                                                 run_evg->run_tp_chdir_safe);
2252         if (evg_u == NULL) {
2253                 return NULL;
2254         }
2255
2256         evg_r = smb_vfs_ev_glue_create_internal(evg_u,
2257                                                 return_evg->return_ev,
2258                                                 run_root->run_ev,
2259                                                 run_root->run_tp_fd_safe,
2260                                                 run_root->run_tp_path_safe,
2261                                                 run_root->run_tp_chdir_safe);
2262         if (evg_r == NULL) {
2263                 return NULL;
2264         }
2265
2266         /*
2267          * evg_r is a boundary with run_ev != return_ev.
2268          * As run_root is also a boundary, we need to
2269          * use run_root->next_glue in order to get
2270          * a glue that stays as root.
2271          *
2272          * The same applies to the chaining of root
2273          * glues.
2274          */
2275         evg_r->next_glue = run_root->next_glue;
2276         evg_r->root_glue = run_root->root_glue;
2277
2278         /*
2279          * evg_r is a boundary with run_ev != return_ev.
2280          * But run_evg is typically not a boundary,
2281          * we use it directly as next_glue.
2282          *
2283          * And the root_glue is the one we constructed above.
2284          */
2285         evg_u->next_glue = run_evg;
2286         evg_u->root_glue = evg_r;
2287
2288         return evg_u;
2289 }
2290
2291 static bool smb_vfs_ev_glue_push_use(const struct smb_vfs_ev_glue *evg,
2292                                      struct tevent_req *req)
2293 {
2294         if (evg->run_ev == evg->return_ev) {
2295                 /*
2296                  * We're already in the correct
2297                  * impersonation environment.
2298                  */
2299                 return true;
2300         }
2301
2302         /*
2303          * Make sure that our callers callback function
2304          * will be called in the return_ev environment.
2305          */
2306         tevent_req_defer_callback(req, evg->return_ev);
2307
2308         /*
2309          * let the event context wrapper do
2310          * the required impersonation.
2311          */
2312         return tevent_context_push_use(evg->run_ev);
2313 }
2314
2315 static void smb_vfs_ev_glue_pop_use(const struct smb_vfs_ev_glue *evg)
2316 {
2317         if (evg->run_ev == evg->return_ev) {
2318                 /*
2319                  * smb_vfs_ev_glue_push_use() didn't
2320                  * change the impersonation environment.
2321                  */
2322                 return;
2323         }
2324
2325         /*
2326          * undo the impersonation
2327          */
2328         tevent_context_pop_use(evg->run_ev);
2329 }
2330
2331 int smb_vfs_call_connect(struct vfs_handle_struct *handle,
2332                          const char *service, const char *user)
2333 {
2334         VFS_FIND(connect);
2335         return handle->fns->connect_fn(handle, service, user);
2336 }
2337
2338 void smb_vfs_call_disconnect(struct vfs_handle_struct *handle)
2339 {
2340         VFS_FIND(disconnect);
2341         handle->fns->disconnect_fn(handle);
2342 }
2343
2344 uint64_t smb_vfs_call_disk_free(struct vfs_handle_struct *handle,
2345                                 const struct smb_filename *smb_fname,
2346                                 uint64_t *bsize,
2347                                 uint64_t *dfree,
2348                                 uint64_t *dsize)
2349 {
2350         VFS_FIND(disk_free);
2351         return handle->fns->disk_free_fn(handle, smb_fname,
2352                         bsize, dfree, dsize);
2353 }
2354
2355 int smb_vfs_call_get_quota(struct vfs_handle_struct *handle,
2356                                 const struct smb_filename *smb_fname,
2357                                 enum SMB_QUOTA_TYPE qtype,
2358                                 unid_t id,
2359                                 SMB_DISK_QUOTA *qt)
2360 {
2361         VFS_FIND(get_quota);
2362         return handle->fns->get_quota_fn(handle, smb_fname, qtype, id, qt);
2363 }
2364
2365 int smb_vfs_call_set_quota(struct vfs_handle_struct *handle,
2366                            enum SMB_QUOTA_TYPE qtype, unid_t id,
2367                            SMB_DISK_QUOTA *qt)
2368 {
2369         VFS_FIND(set_quota);
2370         return handle->fns->set_quota_fn(handle, qtype, id, qt);
2371 }
2372
2373 int smb_vfs_call_get_shadow_copy_data(struct vfs_handle_struct *handle,
2374                                       struct files_struct *fsp,
2375                                       struct shadow_copy_data *shadow_copy_data,
2376                                       bool labels)
2377 {
2378         VFS_FIND(get_shadow_copy_data);
2379         return handle->fns->get_shadow_copy_data_fn(handle, fsp, 
2380                                                     shadow_copy_data,
2381                                                     labels);
2382 }
2383 int smb_vfs_call_statvfs(struct vfs_handle_struct *handle,
2384                         const struct smb_filename *smb_fname,
2385                         struct vfs_statvfs_struct *statbuf)
2386 {
2387         VFS_FIND(statvfs);
2388         return handle->fns->statvfs_fn(handle, smb_fname, statbuf);
2389 }
2390
2391 uint32_t smb_vfs_call_fs_capabilities(struct vfs_handle_struct *handle,
2392                         enum timestamp_set_resolution *p_ts_res)
2393 {
2394         VFS_FIND(fs_capabilities);
2395         return handle->fns->fs_capabilities_fn(handle, p_ts_res);
2396 }
2397
2398 NTSTATUS smb_vfs_call_get_dfs_referrals(struct vfs_handle_struct *handle,
2399                                         struct dfs_GetDFSReferral *r)
2400 {
2401         VFS_FIND(get_dfs_referrals);
2402         return handle->fns->get_dfs_referrals_fn(handle, r);
2403 }
2404
2405 DIR *smb_vfs_call_opendir(struct vfs_handle_struct *handle,
2406                                         const struct smb_filename *smb_fname,
2407                                         const char *mask,
2408                                         uint32_t attributes)
2409 {
2410         VFS_FIND(opendir);
2411         return handle->fns->opendir_fn(handle, smb_fname, mask, attributes);
2412 }
2413
2414 DIR *smb_vfs_call_fdopendir(struct vfs_handle_struct *handle,
2415                                         struct files_struct *fsp,
2416                                         const char *mask,
2417                                         uint32_t attributes)
2418 {
2419         VFS_FIND(fdopendir);
2420         return handle->fns->fdopendir_fn(handle, fsp, mask, attributes);
2421 }
2422
2423 struct dirent *smb_vfs_call_readdir(struct vfs_handle_struct *handle,
2424                                               DIR *dirp,
2425                                               SMB_STRUCT_STAT *sbuf)
2426 {
2427         VFS_FIND(readdir);
2428         return handle->fns->readdir_fn(handle, dirp, sbuf);
2429 }
2430
2431 void smb_vfs_call_seekdir(struct vfs_handle_struct *handle,
2432                           DIR *dirp, long offset)
2433 {
2434         VFS_FIND(seekdir);
2435         handle->fns->seekdir_fn(handle, dirp, offset);
2436 }
2437
2438 long smb_vfs_call_telldir(struct vfs_handle_struct *handle,
2439                           DIR *dirp)
2440 {
2441         VFS_FIND(telldir);
2442         return handle->fns->telldir_fn(handle, dirp);
2443 }
2444
2445 void smb_vfs_call_rewind_dir(struct vfs_handle_struct *handle,
2446                              DIR *dirp)
2447 {
2448         VFS_FIND(rewind_dir);
2449         handle->fns->rewind_dir_fn(handle, dirp);
2450 }
2451
2452 int smb_vfs_call_mkdir(struct vfs_handle_struct *handle,
2453                         const struct smb_filename *smb_fname,
2454                         mode_t mode)
2455 {
2456         VFS_FIND(mkdir);
2457         return handle->fns->mkdir_fn(handle, smb_fname, mode);
2458 }
2459
2460 int smb_vfs_call_rmdir(struct vfs_handle_struct *handle,
2461                         const struct smb_filename *smb_fname)
2462 {
2463         VFS_FIND(rmdir);
2464         return handle->fns->rmdir_fn(handle, smb_fname);
2465 }
2466
2467 int smb_vfs_call_closedir(struct vfs_handle_struct *handle,
2468                           DIR *dir)
2469 {
2470         VFS_FIND(closedir);
2471         return handle->fns->closedir_fn(handle, dir);
2472 }
2473
2474 int smb_vfs_call_open(struct vfs_handle_struct *handle,
2475                       struct smb_filename *smb_fname, struct files_struct *fsp,
2476                       int flags, mode_t mode)
2477 {
2478         VFS_FIND(open);
2479         return handle->fns->open_fn(handle, smb_fname, fsp, flags, mode);
2480 }
2481
2482 NTSTATUS smb_vfs_call_create_file(struct vfs_handle_struct *handle,
2483                                   struct smb_request *req,
2484                                   uint16_t root_dir_fid,
2485                                   struct smb_filename *smb_fname,
2486                                   uint32_t access_mask,
2487                                   uint32_t share_access,
2488                                   uint32_t create_disposition,
2489                                   uint32_t create_options,
2490                                   uint32_t file_attributes,
2491                                   uint32_t oplock_request,
2492                                   struct smb2_lease *lease,
2493                                   uint64_t allocation_size,
2494                                   uint32_t private_flags,
2495                                   struct security_descriptor *sd,
2496                                   struct ea_list *ea_list,
2497                                   files_struct **result,
2498                                   int *pinfo,
2499                                   const struct smb2_create_blobs *in_context_blobs,
2500                                   struct smb2_create_blobs *out_context_blobs)
2501 {
2502         VFS_FIND(create_file);
2503         return handle->fns->create_file_fn(
2504                 handle, req, root_dir_fid, smb_fname, access_mask,
2505                 share_access, create_disposition, create_options,
2506                 file_attributes, oplock_request, lease, allocation_size,
2507                 private_flags, sd, ea_list,
2508                 result, pinfo, in_context_blobs, out_context_blobs);
2509 }
2510
2511 int smb_vfs_call_close(struct vfs_handle_struct *handle,
2512                        struct files_struct *fsp)
2513 {
2514         VFS_FIND(close);
2515         return handle->fns->close_fn(handle, fsp);
2516 }
2517
2518 ssize_t smb_vfs_call_pread(struct vfs_handle_struct *handle,
2519                            struct files_struct *fsp, void *data, size_t n,
2520                            off_t offset)
2521 {
2522         VFS_FIND(pread);
2523         return handle->fns->pread_fn(handle, fsp, data, n, offset);
2524 }
2525
2526 struct smb_vfs_call_pread_state {
2527         ssize_t (*recv_fn)(struct tevent_req *req, struct vfs_aio_state *vfs_aio_state);
2528         ssize_t retval;
2529         struct vfs_aio_state vfs_aio_state;
2530 };
2531
2532 static void smb_vfs_call_pread_done(struct tevent_req *subreq);
2533
2534 struct tevent_req *smb_vfs_call_pread_send(struct vfs_handle_struct *handle,
2535                                            TALLOC_CTX *mem_ctx,
2536                                            struct tevent_context *ev,
2537                                            struct files_struct *fsp,
2538                                            void *data,
2539                                            size_t n, off_t offset)
2540 {
2541         struct tevent_req *req, *subreq;
2542         struct smb_vfs_call_pread_state *state;
2543
2544         req = tevent_req_create(mem_ctx, &state,
2545                                 struct smb_vfs_call_pread_state);
2546         if (req == NULL) {
2547                 return NULL;
2548         }
2549         VFS_FIND(pread_send);
2550         state->recv_fn = handle->fns->pread_recv_fn;
2551
2552         subreq = handle->fns->pread_send_fn(handle, state, ev, fsp, data, n,
2553                                             offset);
2554         if (tevent_req_nomem(subreq, req)) {
2555                 return tevent_req_post(req, ev);
2556         }
2557         tevent_req_set_callback(subreq, smb_vfs_call_pread_done, req);
2558         return req;
2559 }
2560
2561 static void smb_vfs_call_pread_done(struct tevent_req *subreq)
2562 {
2563         struct tevent_req *req = tevent_req_callback_data(
2564                 subreq, struct tevent_req);
2565         struct smb_vfs_call_pread_state *state = tevent_req_data(
2566                 req, struct smb_vfs_call_pread_state);
2567
2568         state->retval = state->recv_fn(subreq, &state->vfs_aio_state);
2569         TALLOC_FREE(subreq);
2570         if (state->retval == -1) {
2571                 tevent_req_error(req, state->vfs_aio_state.error);
2572                 return;
2573         }
2574         tevent_req_done(req);
2575 }
2576
2577 ssize_t SMB_VFS_PREAD_RECV(struct tevent_req *req,
2578                            struct vfs_aio_state *vfs_aio_state)
2579 {
2580         struct smb_vfs_call_pread_state *state = tevent_req_data(
2581                 req, struct smb_vfs_call_pread_state);
2582         ssize_t retval;
2583
2584         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
2585                 tevent_req_received(req);
2586                 return -1;
2587         }
2588         *vfs_aio_state = state->vfs_aio_state;
2589         retval = state->retval;
2590         tevent_req_received(req);
2591         return retval;
2592 }
2593
2594 ssize_t smb_vfs_call_pwrite(struct vfs_handle_struct *handle,
2595                             struct files_struct *fsp, const void *data,
2596                             size_t n, off_t offset)
2597 {
2598         VFS_FIND(pwrite);
2599         return handle->fns->pwrite_fn(handle, fsp, data, n, offset);
2600 }
2601
2602 struct smb_vfs_call_pwrite_state {
2603         ssize_t (*recv_fn)(struct tevent_req *req, struct vfs_aio_state *vfs_aio_state);
2604         ssize_t retval;
2605         struct vfs_aio_state vfs_aio_state;
2606 };
2607
2608 static void smb_vfs_call_pwrite_done(struct tevent_req *subreq);
2609
2610 struct tevent_req *smb_vfs_call_pwrite_send(struct vfs_handle_struct *handle,
2611                                             TALLOC_CTX *mem_ctx,
2612                                             struct tevent_context *ev,
2613                                             struct files_struct *fsp,
2614                                             const void *data,
2615                                             size_t n, off_t offset)
2616 {
2617         struct tevent_req *req, *subreq;
2618         struct smb_vfs_call_pwrite_state *state;
2619
2620         req = tevent_req_create(mem_ctx, &state,
2621                                 struct smb_vfs_call_pwrite_state);
2622         if (req == NULL) {
2623                 return NULL;
2624         }
2625         VFS_FIND(pwrite_send);
2626         state->recv_fn = handle->fns->pwrite_recv_fn;
2627
2628         subreq = handle->fns->pwrite_send_fn(handle, state, ev, fsp, data, n,
2629                                              offset);
2630         if (tevent_req_nomem(subreq, req)) {
2631                 return tevent_req_post(req, ev);
2632         }
2633         tevent_req_set_callback(subreq, smb_vfs_call_pwrite_done, req);
2634         return req;
2635 }
2636
2637 static void smb_vfs_call_pwrite_done(struct tevent_req *subreq)
2638 {
2639         struct tevent_req *req = tevent_req_callback_data(
2640                 subreq, struct tevent_req);
2641         struct smb_vfs_call_pwrite_state *state = tevent_req_data(
2642                 req, struct smb_vfs_call_pwrite_state);
2643
2644         state->retval = state->recv_fn(subreq, &state->vfs_aio_state);
2645         TALLOC_FREE(subreq);
2646         if (state->retval == -1) {
2647                 tevent_req_error(req, state->vfs_aio_state.error);
2648                 return;
2649         }
2650         tevent_req_done(req);
2651 }
2652
2653 ssize_t SMB_VFS_PWRITE_RECV(struct tevent_req *req,
2654                             struct vfs_aio_state *vfs_aio_state)
2655 {
2656         struct smb_vfs_call_pwrite_state *state = tevent_req_data(
2657                 req, struct smb_vfs_call_pwrite_state);
2658         ssize_t retval;
2659
2660         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
2661                 tevent_req_received(req);
2662                 return -1;
2663         }
2664         *vfs_aio_state = state->vfs_aio_state;
2665         retval = state->retval;
2666         tevent_req_received(req);
2667         return retval;
2668 }
2669
2670 off_t smb_vfs_call_lseek(struct vfs_handle_struct *handle,
2671                              struct files_struct *fsp, off_t offset,
2672                              int whence)
2673 {
2674         VFS_FIND(lseek);
2675         return handle->fns->lseek_fn(handle, fsp, offset, whence);
2676 }
2677
2678 ssize_t smb_vfs_call_sendfile(struct vfs_handle_struct *handle, int tofd,
2679                               files_struct *fromfsp, const DATA_BLOB *header,
2680                               off_t offset, size_t count)
2681 {
2682         VFS_FIND(sendfile);
2683         return handle->fns->sendfile_fn(handle, tofd, fromfsp, header, offset,
2684                                         count);
2685 }
2686
2687 ssize_t smb_vfs_call_recvfile(struct vfs_handle_struct *handle, int fromfd,
2688                               files_struct *tofsp, off_t offset,
2689                               size_t count)
2690 {
2691         VFS_FIND(recvfile);
2692         return handle->fns->recvfile_fn(handle, fromfd, tofsp, offset, count);
2693 }
2694
2695 int smb_vfs_call_rename(struct vfs_handle_struct *handle,
2696                         const struct smb_filename *smb_fname_src,
2697                         const struct smb_filename *smb_fname_dst)
2698 {
2699         VFS_FIND(rename);
2700         return handle->fns->rename_fn(handle, smb_fname_src, smb_fname_dst);
2701 }
2702
2703 struct smb_vfs_call_fsync_state {
2704         int (*recv_fn)(struct tevent_req *req, struct vfs_aio_state *vfs_aio_state);
2705         int retval;
2706         struct vfs_aio_state vfs_aio_state;
2707 };
2708
2709 static void smb_vfs_call_fsync_done(struct tevent_req *subreq);
2710
2711 struct tevent_req *smb_vfs_call_fsync_send(struct vfs_handle_struct *handle,
2712                                            TALLOC_CTX *mem_ctx,
2713                                            struct tevent_context *ev,
2714                                            struct files_struct *fsp)
2715 {
2716         struct tevent_req *req, *subreq;
2717         struct smb_vfs_call_fsync_state *state;
2718
2719         req = tevent_req_create(mem_ctx, &state,
2720                                 struct smb_vfs_call_fsync_state);
2721         if (req == NULL) {
2722                 return NULL;
2723         }
2724         VFS_FIND(fsync_send);
2725         state->recv_fn = handle->fns->fsync_recv_fn;
2726
2727         subreq = handle->fns->fsync_send_fn(handle, state, ev, fsp);
2728         if (tevent_req_nomem(subreq, req)) {
2729                 return tevent_req_post(req, ev);
2730         }
2731         tevent_req_set_callback(subreq, smb_vfs_call_fsync_done, req);
2732         return req;
2733 }
2734
2735 static void smb_vfs_call_fsync_done(struct tevent_req *subreq)
2736 {
2737         struct tevent_req *req = tevent_req_callback_data(
2738                 subreq, struct tevent_req);
2739         struct smb_vfs_call_fsync_state *state = tevent_req_data(
2740                 req, struct smb_vfs_call_fsync_state);
2741
2742         state->retval = state->recv_fn(subreq, &state->vfs_aio_state);
2743         TALLOC_FREE(subreq);
2744         if (state->retval == -1) {
2745                 tevent_req_error(req, state->vfs_aio_state.error);
2746                 return;
2747         }
2748         tevent_req_done(req);
2749 }
2750
2751 int SMB_VFS_FSYNC_RECV(struct tevent_req *req, struct vfs_aio_state *vfs_aio_state)
2752 {
2753         struct smb_vfs_call_fsync_state *state = tevent_req_data(
2754                 req, struct smb_vfs_call_fsync_state);
2755         ssize_t retval;
2756
2757         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
2758                 tevent_req_received(req);
2759                 return -1;
2760         }
2761         *vfs_aio_state = state->vfs_aio_state;
2762         retval = state->retval;
2763         tevent_req_received(req);
2764         return retval;
2765 }
2766
2767 /*
2768  * Synchronous version of fsync, built from backend
2769  * async VFS primitives. Uses a temporary sub-event
2770  * context (NOT NESTED).
2771  */
2772
2773 int smb_vfs_fsync_sync(files_struct *fsp)
2774 {
2775         TALLOC_CTX *frame = talloc_stackframe();
2776         struct tevent_req *req = NULL;
2777         struct vfs_aio_state aio_state = { 0 };
2778         int ret = -1;
2779         bool ok;
2780         struct tevent_context *ev = samba_tevent_context_init(frame);
2781
2782         if (ev == NULL) {
2783                 goto out;
2784         }
2785
2786         req = SMB_VFS_FSYNC_SEND(talloc_tos(), ev, fsp);
2787         if (req == NULL) {
2788                 goto out;
2789         }
2790
2791         ok = tevent_req_poll(req, ev);
2792         if (!ok) {
2793                 goto out;
2794         }
2795
2796         ret = SMB_VFS_FSYNC_RECV(req, &aio_state);
2797
2798   out:
2799
2800         TALLOC_FREE(frame);
2801         if (aio_state.error != 0) {
2802                 errno = aio_state.error;
2803         }
2804         return ret;
2805 }
2806
2807 int smb_vfs_call_stat(struct vfs_handle_struct *handle,
2808                       struct smb_filename *smb_fname)
2809 {
2810         VFS_FIND(stat);
2811         return handle->fns->stat_fn(handle, smb_fname);
2812 }
2813
2814 int smb_vfs_call_fstat(struct vfs_handle_struct *handle,
2815                        struct files_struct *fsp, SMB_STRUCT_STAT *sbuf)
2816 {
2817         VFS_FIND(fstat);
2818         return handle->fns->fstat_fn(handle, fsp, sbuf);
2819 }
2820
2821 int smb_vfs_call_lstat(struct vfs_handle_struct *handle,
2822                        struct smb_filename *smb_filename)
2823 {
2824         VFS_FIND(lstat);
2825         return handle->fns->lstat_fn(handle, smb_filename);
2826 }
2827
2828 uint64_t smb_vfs_call_get_alloc_size(struct vfs_handle_struct *handle,
2829                                      struct files_struct *fsp,
2830                                      const SMB_STRUCT_STAT *sbuf)
2831 {
2832         VFS_FIND(get_alloc_size);
2833         return handle->fns->get_alloc_size_fn(handle, fsp, sbuf);
2834 }
2835
2836 int smb_vfs_call_unlink(struct vfs_handle_struct *handle,
2837                         const struct smb_filename *smb_fname)
2838 {
2839         VFS_FIND(unlink);
2840         return handle->fns->unlink_fn(handle, smb_fname);
2841 }
2842
2843 int smb_vfs_call_chmod(struct vfs_handle_struct *handle,
2844                         const struct smb_filename *smb_fname,
2845                         mode_t mode)
2846 {
2847         VFS_FIND(chmod);
2848         return handle->fns->chmod_fn(handle, smb_fname, mode);
2849 }
2850
2851 int smb_vfs_call_fchmod(struct vfs_handle_struct *handle,
2852                         struct files_struct *fsp, mode_t mode)
2853 {
2854         VFS_FIND(fchmod);
2855         return handle->fns->fchmod_fn(handle, fsp, mode);
2856 }
2857
2858 int smb_vfs_call_chown(struct vfs_handle_struct *handle,
2859                         const struct smb_filename *smb_fname,
2860                         uid_t uid,
2861                         gid_t gid)
2862 {
2863         VFS_FIND(chown);
2864         return handle->fns->chown_fn(handle, smb_fname, uid, gid);
2865 }
2866
2867 int smb_vfs_call_fchown(struct vfs_handle_struct *handle,
2868                         struct files_struct *fsp, uid_t uid, gid_t gid)
2869 {
2870         VFS_FIND(fchown);
2871         return handle->fns->fchown_fn(handle, fsp, uid, gid);
2872 }
2873
2874 int smb_vfs_call_lchown(struct vfs_handle_struct *handle,
2875                         const struct smb_filename *smb_fname,
2876                         uid_t uid,
2877                         gid_t gid)
2878 {
2879         VFS_FIND(lchown);
2880         return handle->fns->lchown_fn(handle, smb_fname, uid, gid);
2881 }
2882
2883 NTSTATUS vfs_chown_fsp(files_struct *fsp, uid_t uid, gid_t gid)
2884 {
2885         int ret;
2886         bool as_root = false;
2887         NTSTATUS status;
2888
2889         if (fsp->fh->fd != -1) {
2890                 /* Try fchown. */
2891                 ret = SMB_VFS_FCHOWN(fsp, uid, gid);
2892                 if (ret == 0) {
2893                         return NT_STATUS_OK;
2894                 }
2895                 if (ret == -1 && errno != ENOSYS) {
2896                         return map_nt_error_from_unix(errno);
2897                 }
2898         }
2899
2900         as_root = (geteuid() == 0);
2901
2902         if (as_root) {
2903                 /*
2904                  * We are being asked to chown as root. Make
2905                  * sure we chdir() into the path to pin it,
2906                  * and always act using lchown to ensure we
2907                  * don't deref any symbolic links.
2908                  */
2909                 char *parent_dir = NULL;
2910                 const char *final_component = NULL;
2911                 struct smb_filename *local_smb_fname = NULL;
2912                 struct smb_filename parent_dir_fname = {0};
2913                 struct smb_filename *saved_dir_fname = NULL;
2914
2915                 saved_dir_fname = vfs_GetWd(talloc_tos(),fsp->conn);
2916                 if (!saved_dir_fname) {
2917                         status = map_nt_error_from_unix(errno);
2918                         DEBUG(0,("vfs_chown_fsp: failed to get "
2919                                 "current working directory. Error was %s\n",
2920                                 strerror(errno)));
2921                         return status;
2922                 }
2923
2924                 if (!parent_dirname(talloc_tos(),
2925                                 fsp->fsp_name->base_name,
2926                                 &parent_dir,
2927                                 &final_component)) {
2928                         return NT_STATUS_NO_MEMORY;
2929                 }
2930
2931                 parent_dir_fname = (struct smb_filename) {
2932                         .base_name = parent_dir,
2933                         .flags = fsp->fsp_name->flags
2934                 };
2935
2936                 /* cd into the parent dir to pin it. */
2937                 ret = vfs_ChDir(fsp->conn, &parent_dir_fname);
2938                 if (ret == -1) {
2939                         return map_nt_error_from_unix(errno);
2940                 }
2941
2942                 local_smb_fname = synthetic_smb_fname(talloc_tos(),
2943                                         final_component,
2944                                         NULL,
2945                                         NULL,
2946                                         fsp->fsp_name->flags);
2947                 if (local_smb_fname == NULL) {
2948                         status = NT_STATUS_NO_MEMORY;
2949                         goto out;
2950                 }
2951
2952                 /* Must use lstat here. */
2953                 ret = SMB_VFS_LSTAT(fsp->conn, local_smb_fname);
2954                 if (ret == -1) {
2955                         status = map_nt_error_from_unix(errno);
2956                         goto out;
2957                 }
2958
2959                 /* Ensure it matches the fsp stat. */
2960                 if (!check_same_stat(&local_smb_fname->st,
2961                                 &fsp->fsp_name->st)) {
2962                         status = NT_STATUS_ACCESS_DENIED;
2963                         goto out;
2964                 }
2965
2966                 ret = SMB_VFS_LCHOWN(fsp->conn,
2967                         local_smb_fname,
2968                         uid, gid);
2969
2970                 if (ret == 0) {
2971                         status = NT_STATUS_OK;
2972                 } else {
2973                         status = map_nt_error_from_unix(errno);
2974                 }
2975
2976   out:
2977
2978                 vfs_ChDir(fsp->conn, saved_dir_fname);
2979                 TALLOC_FREE(local_smb_fname);
2980                 TALLOC_FREE(saved_dir_fname);
2981                 TALLOC_FREE(parent_dir);
2982
2983                 return status;
2984         }
2985
2986         if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) {
2987                 ret = SMB_VFS_LCHOWN(fsp->conn,
2988                         fsp->fsp_name,
2989                         uid, gid);
2990         } else {
2991                 ret = SMB_VFS_CHOWN(fsp->conn,
2992                         fsp->fsp_name,
2993                         uid, gid);
2994         }
2995
2996         if (ret == 0) {
2997                 status = NT_STATUS_OK;
2998         } else {
2999                 status = map_nt_error_from_unix(errno);
3000         }
3001         return status;
3002 }
3003
3004 int smb_vfs_call_chdir(struct vfs_handle_struct *handle,
3005                         const struct smb_filename *smb_fname)
3006 {
3007         VFS_FIND(chdir);
3008         return handle->fns->chdir_fn(handle, smb_fname);
3009 }
3010
3011 struct smb_filename *smb_vfs_call_getwd(struct vfs_handle_struct *handle,
3012                                 TALLOC_CTX *ctx)
3013 {
3014         VFS_FIND(getwd);
3015         return handle->fns->getwd_fn(handle, ctx);
3016 }
3017
3018 int smb_vfs_call_ntimes(struct vfs_handle_struct *handle,
3019                         const struct smb_filename *smb_fname,
3020                         struct smb_file_time *ft)
3021 {
3022         VFS_FIND(ntimes);
3023         return handle->fns->ntimes_fn(handle, smb_fname, ft);
3024 }
3025
3026 int smb_vfs_call_ftruncate(struct vfs_handle_struct *handle,
3027                            struct files_struct *fsp, off_t offset)
3028 {
3029         VFS_FIND(ftruncate);
3030         return handle->fns->ftruncate_fn(handle, fsp, offset);
3031 }
3032
3033 int smb_vfs_call_fallocate(struct vfs_handle_struct *handle,
3034                            struct files_struct *fsp,
3035                            uint32_t mode,
3036                            off_t offset,
3037                            off_t len)
3038 {
3039         VFS_FIND(fallocate);
3040         return handle->fns->fallocate_fn(handle, fsp, mode, offset, len);
3041 }
3042
3043 int smb_vfs_call_kernel_flock(struct vfs_handle_struct *handle,
3044                               struct files_struct *fsp, uint32_t share_mode,
3045                               uint32_t access_mask)
3046 {
3047         VFS_FIND(kernel_flock);
3048         return handle->fns->kernel_flock_fn(handle, fsp, share_mode,
3049                                          access_mask);
3050 }
3051
3052 int smb_vfs_call_linux_setlease(struct vfs_handle_struct *handle,
3053                                 struct files_struct *fsp, int leasetype)
3054 {
3055         VFS_FIND(linux_setlease);
3056         return handle->fns->linux_setlease_fn(handle, fsp, leasetype);
3057 }
3058
3059 int smb_vfs_call_symlink(struct vfs_handle_struct *handle,
3060                         const char *link_target,
3061                         const struct smb_filename *new_smb_fname)
3062 {
3063         VFS_FIND(symlink);
3064         return handle->fns->symlink_fn(handle, link_target, new_smb_fname);
3065 }
3066
3067 int smb_vfs_call_readlink(struct vfs_handle_struct *handle,
3068                         const struct smb_filename *smb_fname,
3069                         char *buf,
3070                         size_t bufsiz)
3071 {
3072         VFS_FIND(readlink);
3073         return handle->fns->readlink_fn(handle, smb_fname, buf, bufsiz);
3074 }
3075
3076 int smb_vfs_call_link(struct vfs_handle_struct *handle,
3077                         const struct smb_filename *old_smb_fname,
3078                         const struct smb_filename *new_smb_fname)
3079 {
3080         VFS_FIND(link);
3081         return handle->fns->link_fn(handle, old_smb_fname, new_smb_fname);
3082 }
3083
3084 int smb_vfs_call_mknod(struct vfs_handle_struct *handle,
3085                         const struct smb_filename *smb_fname,
3086                         mode_t mode,
3087                         SMB_DEV_T dev)
3088 {
3089         VFS_FIND(mknod);
3090         return handle->fns->mknod_fn(handle, smb_fname, mode, dev);
3091 }
3092
3093 struct smb_filename *smb_vfs_call_realpath(struct vfs_handle_struct *handle,
3094                         TALLOC_CTX *ctx,
3095                         const struct smb_filename *smb_fname)
3096 {
3097         VFS_FIND(realpath);
3098         return handle->fns->realpath_fn(handle, ctx, smb_fname);
3099 }
3100
3101 int smb_vfs_call_chflags(struct vfs_handle_struct *handle,
3102                         const struct smb_filename *smb_fname,
3103                         unsigned int flags)
3104 {
3105         VFS_FIND(chflags);
3106         return handle->fns->chflags_fn(handle, smb_fname, flags);
3107 }
3108
3109 struct file_id smb_vfs_call_file_id_create(struct vfs_handle_struct *handle,
3110                                            const SMB_STRUCT_STAT *sbuf)
3111 {
3112         VFS_FIND(file_id_create);
3113         return handle->fns->file_id_create_fn(handle, sbuf);
3114 }
3115
3116 NTSTATUS smb_vfs_call_streaminfo(struct vfs_handle_struct *handle,
3117                                  struct files_struct *fsp,
3118                                  const struct smb_filename *smb_fname,
3119                                  TALLOC_CTX *mem_ctx,
3120                                  unsigned int *num_streams,
3121                                  struct stream_struct **streams)
3122 {
3123         VFS_FIND(streaminfo);
3124         return handle->fns->streaminfo_fn(handle, fsp, smb_fname, mem_ctx,
3125                                           num_streams, streams);
3126 }
3127
3128 int smb_vfs_call_get_real_filename(struct vfs_handle_struct *handle,
3129                                    const char *path, const char *name,
3130                                    TALLOC_CTX *mem_ctx, char **found_name)
3131 {
3132         VFS_FIND(get_real_filename);
3133         return handle->fns->get_real_filename_fn(handle, path, name, mem_ctx,
3134                                                  found_name);
3135 }
3136
3137 const char *smb_vfs_call_connectpath(struct vfs_handle_struct *handle,
3138                                  const struct smb_filename *smb_fname)
3139 {
3140         VFS_FIND(connectpath);
3141         return handle->fns->connectpath_fn(handle, smb_fname);
3142 }
3143
3144 bool smb_vfs_call_strict_lock_check(struct vfs_handle_struct *handle,
3145                                     struct files_struct *fsp,
3146                                     struct lock_struct *plock)
3147 {
3148         VFS_FIND(strict_lock_check);
3149         return handle->fns->strict_lock_check_fn(handle, fsp, plock);
3150 }
3151
3152 NTSTATUS smb_vfs_call_translate_name(struct vfs_handle_struct *handle,
3153                                      const char *name,
3154                                      enum vfs_translate_direction direction,
3155                                      TALLOC_CTX *mem_ctx,
3156                                      char **mapped_name)
3157 {
3158         VFS_FIND(translate_name);
3159         return handle->fns->translate_name_fn(handle, name, direction, mem_ctx,
3160                                               mapped_name);
3161 }
3162
3163 NTSTATUS smb_vfs_call_fsctl(struct vfs_handle_struct *handle,
3164                             struct files_struct *fsp,
3165                             TALLOC_CTX *ctx,
3166                             uint32_t function,
3167                             uint16_t req_flags,
3168                             const uint8_t *in_data,
3169                             uint32_t in_len,
3170                             uint8_t **out_data,
3171                             uint32_t max_out_len,
3172                             uint32_t *out_len)
3173 {
3174         VFS_FIND(fsctl);
3175         return handle->fns->fsctl_fn(handle, fsp, ctx, function, req_flags,
3176                                      in_data, in_len, out_data, max_out_len,
3177                                      out_len);
3178 }
3179
3180 NTSTATUS smb_vfs_call_get_dos_attributes(struct vfs_handle_struct *handle,
3181                                          struct smb_filename *smb_fname,
3182                                          uint32_t *dosmode)
3183 {
3184         VFS_FIND(get_dos_attributes);
3185         return handle->fns->get_dos_attributes_fn(handle, smb_fname, dosmode);
3186 }
3187
3188 NTSTATUS smb_vfs_call_fget_dos_attributes(struct vfs_handle_struct *handle,
3189                                           struct files_struct *fsp,
3190                                           uint32_t *dosmode)
3191 {
3192         VFS_FIND(fget_dos_attributes);
3193         return handle->fns->fget_dos_attributes_fn(handle, fsp, dosmode);
3194 }
3195
3196 NTSTATUS smb_vfs_call_set_dos_attributes(struct vfs_handle_struct *handle,
3197                                          const struct smb_filename *smb_fname,
3198                                          uint32_t dosmode)
3199 {
3200         VFS_FIND(set_dos_attributes);
3201         return handle->fns->set_dos_attributes_fn(handle, smb_fname, dosmode);
3202 }
3203
3204 NTSTATUS smb_vfs_call_fset_dos_attributes(struct vfs_handle_struct *handle,
3205                                           struct files_struct *fsp,
3206                                           uint32_t dosmode)
3207 {
3208         VFS_FIND(set_dos_attributes);
3209         return handle->fns->fset_dos_attributes_fn(handle, fsp, dosmode);
3210 }
3211
3212 struct tevent_req *smb_vfs_call_offload_read_send(TALLOC_CTX *mem_ctx,
3213                                                   struct tevent_context *ev,
3214                                                   struct vfs_handle_struct *handle,
3215                                                   struct files_struct *fsp,
3216                                                   uint32_t fsctl,
3217                                                   uint32_t ttl,
3218                                                   off_t offset,
3219                                                   size_t to_copy)
3220 {
3221         VFS_FIND(offload_read_send);
3222         return handle->fns->offload_read_send_fn(mem_ctx, ev, handle,
3223                                                  fsp, fsctl,
3224                                                  ttl, offset, to_copy);
3225 }
3226
3227 NTSTATUS smb_vfs_call_offload_read_recv(struct tevent_req *req,
3228                                         struct vfs_handle_struct *handle,
3229                                         TALLOC_CTX *mem_ctx,
3230                                         DATA_BLOB *token_blob)
3231 {
3232         VFS_FIND(offload_read_recv);
3233         return handle->fns->offload_read_recv_fn(req, handle, mem_ctx, token_blob);
3234 }
3235
3236 struct tevent_req *smb_vfs_call_offload_write_send(struct vfs_handle_struct *handle,
3237                                                    TALLOC_CTX *mem_ctx,
3238                                                    struct tevent_context *ev,
3239                                                    uint32_t fsctl,
3240                                                    DATA_BLOB *token,
3241                                                    off_t transfer_offset,
3242                                                    struct files_struct *dest_fsp,
3243                                                    off_t dest_off,
3244                                                    off_t num)
3245 {
3246         VFS_FIND(offload_write_send);
3247         return handle->fns->offload_write_send_fn(handle, mem_ctx, ev, fsctl,
3248                                                token, transfer_offset,
3249                                                dest_fsp, dest_off, num);
3250 }
3251
3252 NTSTATUS smb_vfs_call_offload_write_recv(struct vfs_handle_struct *handle,
3253                                          struct tevent_req *req,
3254                                          off_t *copied)
3255 {
3256         VFS_FIND(offload_write_recv);
3257         return handle->fns->offload_write_recv_fn(handle, req, copied);
3258 }
3259
3260 struct smb_vfs_call_get_dos_attributes_state {
3261         NTSTATUS (*recv_fn)(struct tevent_req *req,
3262                             struct vfs_aio_state *aio_state,
3263                             uint32_t *dosmode);
3264         struct vfs_aio_state aio_state;
3265         uint32_t dos_attributes;
3266 };
3267
3268 static void smb_vfs_call_get_dos_attributes_done(struct tevent_req *subreq);
3269
3270 struct tevent_req *smb_vfs_call_get_dos_attributes_send(
3271                         TALLOC_CTX *mem_ctx,
3272                         const struct smb_vfs_ev_glue *evg,
3273                         struct vfs_handle_struct *handle,
3274                         files_struct *dir_fsp,
3275                         struct smb_filename *smb_fname)
3276 {
3277         struct tevent_req *req = NULL;
3278         struct smb_vfs_call_get_dos_attributes_state *state = NULL;
3279         struct tevent_req *subreq = NULL;
3280         bool ok;
3281
3282         req = tevent_req_create(mem_ctx, &state,
3283                                 struct smb_vfs_call_get_dos_attributes_state);
3284         if (req == NULL) {
3285                 return NULL;
3286         }
3287
3288         VFS_FIND(get_dos_attributes_send);
3289         state->recv_fn = handle->fns->get_dos_attributes_recv_fn;
3290
3291         ok = smb_vfs_ev_glue_push_use(evg, req);
3292         if (!ok) {
3293                 tevent_req_error(req, EIO);
3294                 return tevent_req_post(req, evg->return_ev);
3295         }
3296
3297         subreq = handle->fns->get_dos_attributes_send_fn(mem_ctx,
3298                                                          evg->next_glue,
3299                                                          handle,
3300                                                          dir_fsp,
3301                                                          smb_fname);
3302         smb_vfs_ev_glue_pop_use(evg);
3303
3304         if (tevent_req_nomem(subreq, req)) {
3305                 return tevent_req_post(req, evg->return_ev);
3306         }
3307         tevent_req_set_callback(subreq,
3308                                 smb_vfs_call_get_dos_attributes_done,
3309                                 req);
3310
3311         return req;
3312 }
3313
3314 static void smb_vfs_call_get_dos_attributes_done(struct tevent_req *subreq)
3315 {
3316         struct tevent_req *req =
3317                 tevent_req_callback_data(subreq,
3318                 struct tevent_req);
3319         struct smb_vfs_call_get_dos_attributes_state *state =
3320                 tevent_req_data(req,
3321                 struct smb_vfs_call_get_dos_attributes_state);
3322         NTSTATUS status;
3323
3324         status = state->recv_fn(subreq,
3325                                 &state->aio_state,
3326                                 &state->dos_attributes);
3327         TALLOC_FREE(subreq);
3328         if (tevent_req_nterror(req, status)) {
3329                 return;
3330         }
3331
3332         tevent_req_done(req);
3333 }
3334
3335 NTSTATUS smb_vfs_call_get_dos_attributes_recv(
3336                 struct tevent_req *req,
3337                 struct vfs_aio_state *aio_state,
3338                 uint32_t *dos_attributes)
3339 {
3340         struct smb_vfs_call_get_dos_attributes_state *state =
3341                 tevent_req_data(req,
3342                 struct smb_vfs_call_get_dos_attributes_state);
3343         NTSTATUS status;
3344
3345         if (tevent_req_is_nterror(req, &status)) {
3346                 tevent_req_received(req);
3347                 return status;
3348         }
3349
3350         *aio_state = state->aio_state;
3351         *dos_attributes = state->dos_attributes;
3352         tevent_req_received(req);
3353         return NT_STATUS_OK;
3354 }
3355
3356 NTSTATUS smb_vfs_call_get_compression(vfs_handle_struct *handle,
3357                                       TALLOC_CTX *mem_ctx,
3358                                       struct files_struct *fsp,
3359                                       struct smb_filename *smb_fname,
3360                                       uint16_t *_compression_fmt)
3361 {
3362         VFS_FIND(get_compression);
3363         return handle->fns->get_compression_fn(handle, mem_ctx, fsp, smb_fname,
3364                                                _compression_fmt);
3365 }
3366
3367 NTSTATUS smb_vfs_call_set_compression(vfs_handle_struct *handle,
3368                                       TALLOC_CTX *mem_ctx,
3369                                       struct files_struct *fsp,
3370                                       uint16_t compression_fmt)
3371 {
3372         VFS_FIND(set_compression);
3373         return handle->fns->set_compression_fn(handle, mem_ctx, fsp,
3374                                                compression_fmt);
3375 }
3376
3377 NTSTATUS smb_vfs_call_snap_check_path(vfs_handle_struct *handle,
3378                                       TALLOC_CTX *mem_ctx,
3379                                       const char *service_path,
3380                                       char **base_volume)
3381 {
3382         VFS_FIND(snap_check_path);
3383         return handle->fns->snap_check_path_fn(handle, mem_ctx, service_path,
3384                                                base_volume);
3385 }
3386
3387 NTSTATUS smb_vfs_call_snap_create(struct vfs_handle_struct *handle,
3388                                   TALLOC_CTX *mem_ctx,
3389                                   const char *base_volume,
3390                                   time_t *tstamp,
3391                                   bool rw,
3392                                   char **base_path,
3393                                   char **snap_path)
3394 {
3395         VFS_FIND(snap_create);
3396         return handle->fns->snap_create_fn(handle, mem_ctx, base_volume, tstamp,
3397                                            rw, base_path, snap_path);
3398 }
3399
3400 NTSTATUS smb_vfs_call_snap_delete(struct vfs_handle_struct *handle,
3401                                   TALLOC_CTX *mem_ctx,
3402                                   char *base_path,
3403                                   char *snap_path)
3404 {
3405         VFS_FIND(snap_delete);
3406         return handle->fns->snap_delete_fn(handle, mem_ctx, base_path,
3407                                            snap_path);
3408 }
3409
3410 NTSTATUS smb_vfs_call_fget_nt_acl(struct vfs_handle_struct *handle,
3411                                   struct files_struct *fsp,
3412                                   uint32_t security_info,
3413                                   TALLOC_CTX *mem_ctx,
3414                                   struct security_descriptor **ppdesc)
3415 {
3416         VFS_FIND(fget_nt_acl);
3417         return handle->fns->fget_nt_acl_fn(handle, fsp, security_info,
3418                                            mem_ctx, ppdesc);
3419 }
3420
3421 NTSTATUS smb_vfs_call_get_nt_acl(struct vfs_handle_struct *handle,
3422                                  const struct smb_filename *smb_fname,
3423                                  uint32_t security_info,
3424                                  TALLOC_CTX *mem_ctx,
3425                                  struct security_descriptor **ppdesc)
3426 {
3427         VFS_FIND(get_nt_acl);
3428         return handle->fns->get_nt_acl_fn(handle,
3429                                 smb_fname,
3430                                 security_info,
3431                                 mem_ctx,
3432                                 ppdesc);
3433 }
3434
3435 NTSTATUS smb_vfs_call_fset_nt_acl(struct vfs_handle_struct *handle,
3436                                   struct files_struct *fsp,
3437                                   uint32_t security_info_sent,
3438                                   const struct security_descriptor *psd)
3439 {
3440         VFS_FIND(fset_nt_acl);
3441         return handle->fns->fset_nt_acl_fn(handle, fsp, security_info_sent, 
3442                                            psd);
3443 }
3444
3445 NTSTATUS smb_vfs_call_audit_file(struct vfs_handle_struct *handle,
3446                                  struct smb_filename *file,
3447                                  struct security_acl *sacl,
3448                                  uint32_t access_requested,
3449                                  uint32_t access_denied)
3450 {
3451         VFS_FIND(audit_file);
3452         return handle->fns->audit_file_fn(handle, 
3453                                           file, 
3454                                           sacl, 
3455                                           access_requested, 
3456                                           access_denied);
3457 }
3458
3459 SMB_ACL_T smb_vfs_call_sys_acl_get_file(struct vfs_handle_struct *handle,
3460                                         const struct smb_filename *smb_fname,
3461                                         SMB_ACL_TYPE_T type,
3462                                         TALLOC_CTX *mem_ctx)
3463 {
3464         VFS_FIND(sys_acl_get_file);
3465         return handle->fns->sys_acl_get_file_fn(handle, smb_fname, type, mem_ctx);
3466 }
3467
3468 SMB_ACL_T smb_vfs_call_sys_acl_get_fd(struct vfs_handle_struct *handle,
3469                                       struct files_struct *fsp,
3470                                       TALLOC_CTX *mem_ctx)
3471 {
3472         VFS_FIND(sys_acl_get_fd);
3473         return handle->fns->sys_acl_get_fd_fn(handle, fsp, mem_ctx);
3474 }
3475
3476 int smb_vfs_call_sys_acl_blob_get_file(struct vfs_handle_struct *handle,
3477                                 const struct smb_filename *smb_fname,
3478                                 TALLOC_CTX *mem_ctx,
3479                                 char **blob_description,
3480                                 DATA_BLOB *blob)
3481 {
3482         VFS_FIND(sys_acl_blob_get_file);
3483         return handle->fns->sys_acl_blob_get_file_fn(handle, smb_fname,
3484                         mem_ctx, blob_description, blob);
3485 }
3486
3487 int smb_vfs_call_sys_acl_blob_get_fd(struct vfs_handle_struct *handle,
3488                                      struct files_struct *fsp,
3489                                      TALLOC_CTX *mem_ctx, 
3490                                      char **blob_description,
3491                                      DATA_BLOB *blob)
3492 {
3493         VFS_FIND(sys_acl_blob_get_fd);
3494         return handle->fns->sys_acl_blob_get_fd_fn(handle, fsp, mem_ctx, blob_description, blob);
3495 }
3496
3497 int smb_vfs_call_sys_acl_set_file(struct vfs_handle_struct *handle,
3498                                 const struct smb_filename *smb_fname,
3499                                 SMB_ACL_TYPE_T acltype,
3500                                 SMB_ACL_T theacl)
3501 {
3502         VFS_FIND(sys_acl_set_file);
3503         return handle->fns->sys_acl_set_file_fn(handle, smb_fname,
3504                                 acltype, theacl);
3505 }
3506
3507 int smb_vfs_call_sys_acl_set_fd(struct vfs_handle_struct *handle,
3508                                 struct files_struct *fsp, SMB_ACL_T theacl)
3509 {
3510         VFS_FIND(sys_acl_set_fd);
3511         return handle->fns->sys_acl_set_fd_fn(handle, fsp, theacl);
3512 }
3513
3514 int smb_vfs_call_sys_acl_delete_def_file(struct vfs_handle_struct *handle,
3515                                 const struct smb_filename *smb_fname)
3516 {
3517         VFS_FIND(sys_acl_delete_def_file);
3518         return handle->fns->sys_acl_delete_def_file_fn(handle, smb_fname);
3519 }
3520
3521 ssize_t smb_vfs_call_getxattr(struct vfs_handle_struct *handle,
3522                                 const struct smb_filename *smb_fname,
3523                                 const char *name,
3524                                 void *value,
3525                                 size_t size)
3526 {
3527         VFS_FIND(getxattr);
3528         return handle->fns->getxattr_fn(handle, smb_fname, name, value, size);
3529 }
3530
3531
3532 struct smb_vfs_call_getxattrat_state {
3533         ssize_t (*recv_fn)(struct tevent_req *req,
3534                            struct vfs_aio_state *aio_state,
3535                            TALLOC_CTX *mem_ctx,
3536                            uint8_t **xattr_value);
3537         ssize_t retval;
3538         uint8_t *xattr_value;
3539         struct vfs_aio_state aio_state;
3540 };
3541
3542 static void smb_vfs_call_getxattrat_done(struct tevent_req *subreq);
3543
3544 struct tevent_req *smb_vfs_call_getxattrat_send(
3545                         TALLOC_CTX *mem_ctx,
3546                         const struct smb_vfs_ev_glue *evg,
3547                         struct vfs_handle_struct *handle,
3548                         files_struct *dir_fsp,
3549                         const struct smb_filename *smb_fname,
3550                         const char *xattr_name,
3551                         size_t alloc_hint)
3552 {
3553         struct tevent_req *req = NULL;
3554         struct smb_vfs_call_getxattrat_state *state = NULL;
3555         struct tevent_req *subreq = NULL;
3556         bool ok;
3557
3558         req = tevent_req_create(mem_ctx, &state,
3559                                 struct smb_vfs_call_getxattrat_state);
3560         if (req == NULL) {
3561                 return NULL;
3562         }
3563
3564         VFS_FIND(getxattrat_send);
3565         state->recv_fn = handle->fns->getxattrat_recv_fn;
3566
3567         ok = smb_vfs_ev_glue_push_use(evg, req);
3568         if (!ok) {
3569                 tevent_req_error(req, EIO);
3570                 return tevent_req_post(req, evg->return_ev);
3571         }
3572
3573         subreq = handle->fns->getxattrat_send_fn(mem_ctx,
3574                                                  evg->next_glue,
3575                                                  handle,
3576                                                  dir_fsp,
3577                                                  smb_fname,
3578                                                  xattr_name,
3579                                                  alloc_hint);
3580         smb_vfs_ev_glue_pop_use(evg);
3581
3582         if (tevent_req_nomem(subreq, req)) {
3583                 return tevent_req_post(req, evg->return_ev);
3584         }
3585         tevent_req_set_callback(subreq, smb_vfs_call_getxattrat_done, req);
3586         return req;
3587 }
3588
3589 static void smb_vfs_call_getxattrat_done(struct tevent_req *subreq)
3590 {
3591         struct tevent_req *req = tevent_req_callback_data(
3592                 subreq, struct tevent_req);
3593         struct smb_vfs_call_getxattrat_state *state = tevent_req_data(
3594                 req, struct smb_vfs_call_getxattrat_state);
3595
3596         state->retval = state->recv_fn(subreq,
3597                                        &state->aio_state,
3598                                        state,
3599                                        &state->xattr_value);
3600         TALLOC_FREE(subreq);
3601         if (state->retval == -1) {
3602                 tevent_req_error(req, state->aio_state.error);
3603                 return;
3604         }
3605
3606         tevent_req_done(req);
3607 }
3608
3609 ssize_t smb_vfs_call_getxattrat_recv(struct tevent_req *req,
3610                                      struct vfs_aio_state *aio_state,
3611                                      TALLOC_CTX *mem_ctx,
3612                                      uint8_t **xattr_value)
3613 {
3614         struct smb_vfs_call_getxattrat_state *state = tevent_req_data(
3615                 req, struct smb_vfs_call_getxattrat_state);
3616         size_t xattr_size;
3617
3618         if (tevent_req_is_unix_error(req, &aio_state->error)) {
3619                 tevent_req_received(req);
3620                 return -1;
3621         }
3622
3623         *aio_state = state->aio_state;
3624         xattr_size = state->retval;
3625         if (xattr_value != NULL) {
3626                 *xattr_value = talloc_move(mem_ctx, &state->xattr_value);
3627         }
3628
3629         tevent_req_received(req);
3630         return xattr_size;
3631 }
3632
3633 ssize_t smb_vfs_call_fgetxattr(struct vfs_handle_struct *handle,
3634                                struct files_struct *fsp, const char *name,
3635                                void *value, size_t size)
3636 {
3637         VFS_FIND(fgetxattr);
3638         return handle->fns->fgetxattr_fn(handle, fsp, name, value, size);
3639 }
3640
3641 ssize_t smb_vfs_call_listxattr(struct vfs_handle_struct *handle,
3642                                 const struct smb_filename *smb_fname,
3643                                 char *list,
3644                                 size_t size)
3645 {
3646         VFS_FIND(listxattr);
3647         return handle->fns->listxattr_fn(handle, smb_fname, list, size);
3648 }
3649
3650 ssize_t smb_vfs_call_flistxattr(struct vfs_handle_struct *handle,
3651                                 struct files_struct *fsp, char *list,
3652                                 size_t size)
3653 {
3654         VFS_FIND(flistxattr);
3655         return handle->fns->flistxattr_fn(handle, fsp, list, size);
3656 }
3657
3658 int smb_vfs_call_removexattr(struct vfs_handle_struct *handle,
3659                                 const struct smb_filename *smb_fname,
3660                                 const char *name)
3661 {
3662         VFS_FIND(removexattr);
3663         return handle->fns->removexattr_fn(handle, smb_fname, name);
3664 }
3665
3666 int smb_vfs_call_fremovexattr(struct vfs_handle_struct *handle,
3667                               struct files_struct *fsp, const char *name)
3668 {
3669         VFS_FIND(fremovexattr);
3670         return handle->fns->fremovexattr_fn(handle, fsp, name);
3671 }
3672
3673 int smb_vfs_call_setxattr(struct vfs_handle_struct *handle,
3674                         const struct smb_filename *smb_fname,
3675                         const char *name,
3676                         const void *value,
3677                         size_t size,
3678                         int flags)
3679 {
3680         VFS_FIND(setxattr);
3681         return handle->fns->setxattr_fn(handle, smb_fname,
3682                         name, value, size, flags);
3683 }
3684
3685 int smb_vfs_call_fsetxattr(struct vfs_handle_struct *handle,
3686                            struct files_struct *fsp, const char *name,
3687                            const void *value, size_t size, int flags)
3688 {
3689         VFS_FIND(fsetxattr);
3690         return handle->fns->fsetxattr_fn(handle, fsp, name, value, size, flags);
3691 }
3692
3693 bool smb_vfs_call_aio_force(struct vfs_handle_struct *handle,
3694                             struct files_struct *fsp)
3695 {
3696         VFS_FIND(aio_force);
3697         return handle->fns->aio_force_fn(handle, fsp);
3698 }
3699
3700 NTSTATUS smb_vfs_call_durable_cookie(struct vfs_handle_struct *handle,
3701                                      struct files_struct *fsp,
3702                                      TALLOC_CTX *mem_ctx,
3703                                      DATA_BLOB *cookie)
3704 {
3705         VFS_FIND(durable_cookie);
3706         return handle->fns->durable_cookie_fn(handle, fsp, mem_ctx, cookie);
3707 }
3708
3709 NTSTATUS smb_vfs_call_durable_disconnect(struct vfs_handle_struct *handle,
3710                                          struct files_struct *fsp,
3711                                          const DATA_BLOB old_cookie,
3712                                          TALLOC_CTX *mem_ctx,
3713                                          DATA_BLOB *new_cookie)
3714 {
3715         VFS_FIND(durable_disconnect);
3716         return handle->fns->durable_disconnect_fn(handle, fsp, old_cookie,
3717                                                   mem_ctx, new_cookie);
3718 }
3719
3720 NTSTATUS smb_vfs_call_durable_reconnect(struct vfs_handle_struct *handle,
3721                                         struct smb_request *smb1req,
3722                                         struct smbXsrv_open *op,
3723                                         const DATA_BLOB old_cookie,
3724                                         TALLOC_CTX *mem_ctx,
3725                                         struct files_struct **fsp,
3726                                         DATA_BLOB *new_cookie)
3727 {
3728         VFS_FIND(durable_reconnect);
3729         return handle->fns->durable_reconnect_fn(handle, smb1req, op,
3730                                                  old_cookie, mem_ctx, fsp,
3731                                                  new_cookie);
3732 }
3733
3734 NTSTATUS smb_vfs_call_readdir_attr(struct vfs_handle_struct *handle,
3735                                    const struct smb_filename *fname,
3736                                    TALLOC_CTX *mem_ctx,
3737                                    struct readdir_attr_data **attr_data)
3738 {
3739         VFS_FIND(readdir_attr);
3740         return handle->fns->readdir_attr_fn(handle, fname, mem_ctx, attr_data);
3741 }