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