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