s3 vfs: Add a destructor to the fsp extension data API
[samba.git] / source3 / smbd / vfs.c
1 /*
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    VFS initialisation and support functions
5    Copyright (C) Tim Potter 1999
6    Copyright (C) Alexander Bokovoy 2002
7    Copyright (C) James Peach 2006
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
22    This work was sponsored by Optifacio Software Services, Inc.
23 */
24
25 #include "includes.h"
26 #include "smbd/globals.h"
27
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_VFS
30
31 static_decl_vfs;
32
33 struct vfs_init_function_entry {
34         char *name;
35         const vfs_op_tuple *vfs_op_tuples;
36         struct vfs_init_function_entry *prev, *next;
37 };
38
39 /****************************************************************************
40     maintain the list of available backends
41 ****************************************************************************/
42
43 static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name)
44 {
45         struct vfs_init_function_entry *entry = backends;
46
47         DEBUG(10, ("vfs_find_backend_entry called for %s\n", name));
48  
49         while(entry) {
50                 if (strcmp(entry->name, name)==0) return entry;
51                 entry = entry->next;
52         }
53
54         return NULL;
55 }
56
57 NTSTATUS smb_register_vfs(int version, const char *name, const vfs_op_tuple *vfs_op_tuples)
58 {
59         struct vfs_init_function_entry *entry = backends;
60
61         if ((version != SMB_VFS_INTERFACE_VERSION)) {
62                 DEBUG(0, ("Failed to register vfs module.\n"
63                           "The module was compiled against SMB_VFS_INTERFACE_VERSION %d,\n"
64                           "current SMB_VFS_INTERFACE_VERSION is %d.\n"
65                           "Please recompile against the current Samba Version!\n",  
66                           version, SMB_VFS_INTERFACE_VERSION));
67                 return NT_STATUS_OBJECT_TYPE_MISMATCH;
68         }
69
70         if (!name || !name[0] || !vfs_op_tuples) {
71                 DEBUG(0,("smb_register_vfs() called with NULL pointer or empty name!\n"));
72                 return NT_STATUS_INVALID_PARAMETER;
73         }
74
75         if (vfs_find_backend_entry(name)) {
76                 DEBUG(0,("VFS module %s already loaded!\n", name));
77                 return NT_STATUS_OBJECT_NAME_COLLISION;
78         }
79
80         entry = SMB_XMALLOC_P(struct vfs_init_function_entry);
81         entry->name = smb_xstrdup(name);
82         entry->vfs_op_tuples = vfs_op_tuples;
83
84         DLIST_ADD(backends, entry);
85         DEBUG(5, ("Successfully added vfs backend '%s'\n", name));
86         return NT_STATUS_OK;
87 }
88
89 /****************************************************************************
90   initialise default vfs hooks
91 ****************************************************************************/
92
93 static void vfs_init_default(connection_struct *conn)
94 {
95         DEBUG(3, ("Initialising default vfs hooks\n"));
96         vfs_init_custom(conn, DEFAULT_VFS_MODULE_NAME);
97 }
98
99 /****************************************************************************
100   initialise custom vfs hooks
101  ****************************************************************************/
102
103 static inline void vfs_set_operation(struct vfs_ops * vfs, vfs_op_type which,
104                                 struct vfs_handle_struct * handle, void * op)
105 {
106         ((struct vfs_handle_struct **)&vfs->handles)[which] = handle;
107         ((void **)(void *)&vfs->ops)[which] = op;
108 }
109
110 bool vfs_init_custom(connection_struct *conn, const char *vfs_object)
111 {
112         const vfs_op_tuple *ops;
113         char *module_path = NULL;
114         char *module_name = NULL;
115         char *module_param = NULL, *p;
116         int i;
117         vfs_handle_struct *handle;
118         const struct vfs_init_function_entry *entry;
119         
120         if (!conn||!vfs_object||!vfs_object[0]) {
121                 DEBUG(0,("vfs_init_custon() called with NULL pointer or emtpy vfs_object!\n"));
122                 return False;
123         }
124
125         if(!backends) {
126                 static_init_vfs;
127         }
128
129         DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object));
130
131         module_path = smb_xstrdup(vfs_object);
132
133         p = strchr_m(module_path, ':');
134
135         if (p) {
136                 *p = 0;
137                 module_param = p+1;
138                 trim_char(module_param, ' ', ' ');
139         }
140
141         trim_char(module_path, ' ', ' ');
142
143         module_name = smb_xstrdup(module_path);
144
145         if ((module_name[0] == '/') &&
146             (strcmp(module_path, DEFAULT_VFS_MODULE_NAME) != 0)) {
147
148                 /*
149                  * Extract the module name from the path. Just use the base
150                  * name of the last path component.
151                  */
152
153                 SAFE_FREE(module_name);
154                 module_name = smb_xstrdup(strrchr_m(module_path, '/')+1);
155
156                 p = strchr_m(module_name, '.');
157
158                 if (p != NULL) {
159                         *p = '\0';
160                 }
161         }
162
163         /* First, try to load the module with the new module system */
164         if((entry = vfs_find_backend_entry(module_name)) || 
165            (NT_STATUS_IS_OK(smb_probe_module("vfs", module_path)) &&
166                 (entry = vfs_find_backend_entry(module_name)))) {
167
168                 DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
169                 
170                 if ((ops = entry->vfs_op_tuples) == NULL) {
171                         DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object));
172                         goto fail;
173                 }
174         } else {
175                 DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
176                 goto fail;
177         }
178
179         handle = TALLOC_ZERO_P(conn, vfs_handle_struct);
180         if (!handle) {
181                 DEBUG(0,("TALLOC_ZERO() failed!\n"));
182                 goto fail;
183         }
184         memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops));
185         handle->conn = conn;
186         if (module_param) {
187                 handle->param = talloc_strdup(conn, module_param);
188         }
189         DLIST_ADD(conn->vfs_handles, handle);
190
191         for(i=0; ops[i].op != NULL; i++) {
192                 DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer));
193                 if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) {
194                         /* If this operation was already made opaque by different module, it
195                          * will be overridden here.
196                          */
197                         DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object));
198                         vfs_set_operation(&conn->vfs_opaque, ops[i].type, handle, ops[i].op);
199                 }
200                 /* Change current VFS disposition*/
201                 DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object));
202                 vfs_set_operation(&conn->vfs, ops[i].type, handle, ops[i].op);
203         }
204
205         SAFE_FREE(module_path);
206         SAFE_FREE(module_name);
207         return True;
208
209  fail:
210         SAFE_FREE(module_path);
211         SAFE_FREE(module_name);
212         return False;
213 }
214
215 /*****************************************************************
216  Allow VFS modules to extend files_struct with VFS-specific state.
217  This will be ok for small numbers of extensions, but might need to
218  be refactored if it becomes more widely used.
219 ******************************************************************/
220
221 #define EXT_DATA_AREA(e) ((uint8 *)(e) + sizeof(struct vfs_fsp_data))
222
223 void *vfs_add_fsp_extension_notype(vfs_handle_struct *handle,
224                                    files_struct *fsp, size_t ext_size,
225                                    void (*destroy_fn)(void *p_data))
226 {
227         struct vfs_fsp_data *ext;
228         void * ext_data;
229
230         /* Prevent VFS modules adding multiple extensions. */
231         if ((ext_data = vfs_fetch_fsp_extension(handle, fsp))) {
232                 return ext_data;
233         }
234
235         ext = (struct vfs_fsp_data *)TALLOC_ZERO(
236                 handle->conn, sizeof(struct vfs_fsp_data) + ext_size);
237         if (ext == NULL) {
238                 return NULL;
239         }
240
241         ext->owner = handle;
242         ext->next = fsp->vfs_extension;
243         ext->destroy = destroy_fn;
244         fsp->vfs_extension = ext;
245         return EXT_DATA_AREA(ext);
246 }
247
248 void vfs_remove_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
249 {
250         struct vfs_fsp_data *curr;
251         struct vfs_fsp_data *prev;
252
253         for (curr = fsp->vfs_extension, prev = NULL;
254              curr;
255              prev = curr, curr = curr->next) {
256                 if (curr->owner == handle) {
257                     if (prev) {
258                             prev->next = curr->next;
259                     } else {
260                             fsp->vfs_extension = curr->next;
261                     }
262                     if (curr->destroy) {
263                             curr->destroy(EXT_DATA_AREA(curr));
264                     }
265                     TALLOC_FREE(curr);
266                     return;
267                 }
268         }
269 }
270
271 void *vfs_memctx_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
272 {
273         struct vfs_fsp_data *head;
274
275         for (head = fsp->vfs_extension; head; head = head->next) {
276                 if (head->owner == handle) {
277                         return head;
278                 }
279         }
280
281         return NULL;
282 }
283
284 void *vfs_fetch_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
285 {
286         struct vfs_fsp_data *head;
287
288         head = (struct vfs_fsp_data *)vfs_memctx_fsp_extension(handle, fsp);
289         if (head != NULL) {
290                 return EXT_DATA_AREA(head);
291         }
292
293         return NULL;
294 }
295
296 #undef EXT_DATA_AREA
297
298 /*****************************************************************
299  Generic VFS init.
300 ******************************************************************/
301
302 bool smbd_vfs_init(connection_struct *conn)
303 {
304         const char **vfs_objects;
305         unsigned int i = 0;
306         int j = 0;
307         
308         /* Normal share - initialise with disk access functions */
309         vfs_init_default(conn);
310         vfs_objects = lp_vfs_objects(SNUM(conn));
311
312         /* Override VFS functions if 'vfs object' was not specified*/
313         if (!vfs_objects || !vfs_objects[0])
314                 return True;
315         
316         for (i=0; vfs_objects[i] ;) {
317                 i++;
318         }
319
320         for (j=i-1; j >= 0; j--) {
321                 if (!vfs_init_custom(conn, vfs_objects[j])) {
322                         DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects[j]));
323                         return False;
324                 }
325         }
326         return True;
327 }
328
329 /*******************************************************************
330  Check if directory exists.
331 ********************************************************************/
332
333 bool vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
334 {
335         SMB_STRUCT_STAT st2;
336         bool ret;
337
338         if (!st)
339                 st = &st2;
340
341         if (SMB_VFS_STAT(conn,dname,st) != 0)
342                 return(False);
343
344         ret = S_ISDIR(st->st_mode);
345         if(!ret)
346                 errno = ENOTDIR;
347
348         return ret;
349 }
350
351 /*******************************************************************
352  Check if an object exists in the vfs.
353 ********************************************************************/
354
355 bool vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
356 {
357         SMB_STRUCT_STAT st;
358
359         if (!sbuf)
360                 sbuf = &st;
361
362         ZERO_STRUCTP(sbuf);
363
364         if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
365                 return(False);
366         return True;
367 }
368
369 /*******************************************************************
370  Check if a file exists in the vfs.
371 ********************************************************************/
372
373 bool vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
374 {
375         SMB_STRUCT_STAT st;
376
377         if (!sbuf)
378                 sbuf = &st;
379
380         ZERO_STRUCTP(sbuf);
381
382         if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
383                 return False;
384         return(S_ISREG(sbuf->st_mode));
385 }
386
387 /****************************************************************************
388  Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
389 ****************************************************************************/
390
391 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
392 {
393         size_t total=0;
394
395         while (total < byte_count)
396         {
397                 ssize_t ret = SMB_VFS_READ(fsp, buf + total,
398                                            byte_count - total);
399
400                 if (ret == 0) return total;
401                 if (ret == -1) {
402                         if (errno == EINTR)
403                                 continue;
404                         else
405                                 return -1;
406                 }
407                 total += ret;
408         }
409         return (ssize_t)total;
410 }
411
412 ssize_t vfs_pread_data(files_struct *fsp, char *buf,
413                 size_t byte_count, SMB_OFF_T offset)
414 {
415         size_t total=0;
416
417         while (total < byte_count)
418         {
419                 ssize_t ret = SMB_VFS_PREAD(fsp, buf + total,
420                                         byte_count - total, offset + total);
421
422                 if (ret == 0) return total;
423                 if (ret == -1) {
424                         if (errno == EINTR)
425                                 continue;
426                         else
427                                 return -1;
428                 }
429                 total += ret;
430         }
431         return (ssize_t)total;
432 }
433
434 /****************************************************************************
435  Write data to a fd on the vfs.
436 ****************************************************************************/
437
438 ssize_t vfs_write_data(struct smb_request *req,
439                         files_struct *fsp,
440                         const char *buffer,
441                         size_t N)
442 {
443         size_t total=0;
444         ssize_t ret;
445
446         if (req && req->unread_bytes) {
447                 SMB_ASSERT(req->unread_bytes == N);
448                 /* VFS_RECVFILE must drain the socket
449                  * before returning. */
450                 req->unread_bytes = 0;
451                 return SMB_VFS_RECVFILE(smbd_server_fd(),
452                                         fsp,
453                                         (SMB_OFF_T)-1,
454                                         N);
455         }
456
457         while (total < N) {
458                 ret = SMB_VFS_WRITE(fsp, buffer + total, N - total);
459
460                 if (ret == -1)
461                         return -1;
462                 if (ret == 0)
463                         return total;
464
465                 total += ret;
466         }
467         return (ssize_t)total;
468 }
469
470 ssize_t vfs_pwrite_data(struct smb_request *req,
471                         files_struct *fsp,
472                         const char *buffer,
473                         size_t N,
474                         SMB_OFF_T offset)
475 {
476         size_t total=0;
477         ssize_t ret;
478
479         if (req && req->unread_bytes) {
480                 SMB_ASSERT(req->unread_bytes == N);
481                 /* VFS_RECVFILE must drain the socket
482                  * before returning. */
483                 req->unread_bytes = 0;
484                 return SMB_VFS_RECVFILE(smbd_server_fd(),
485                                         fsp,
486                                         offset,
487                                         N);
488         }
489
490         while (total < N) {
491                 ret = SMB_VFS_PWRITE(fsp, buffer + total, N - total,
492                                      offset + total);
493
494                 if (ret == -1)
495                         return -1;
496                 if (ret == 0)
497                         return total;
498
499                 total += ret;
500         }
501         return (ssize_t)total;
502 }
503 /****************************************************************************
504  An allocate file space call using the vfs interface.
505  Allocates space for a file from a filedescriptor.
506  Returns 0 on success, -1 on failure.
507 ****************************************************************************/
508
509 int vfs_allocate_file_space(files_struct *fsp, uint64_t len)
510 {
511         int ret;
512         SMB_STRUCT_STAT st;
513         connection_struct *conn = fsp->conn;
514         uint64_t space_avail;
515         uint64_t bsize,dfree,dsize;
516
517         release_level_2_oplocks_on_change(fsp);
518
519         /*
520          * Actually try and commit the space on disk....
521          */
522
523         DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
524
525         if (((SMB_OFF_T)len) < 0) {
526                 DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
527                 errno = EINVAL;
528                 return -1;
529         }
530
531         ret = SMB_VFS_FSTAT(fsp, &st);
532         if (ret == -1)
533                 return ret;
534
535         if (len == (uint64_t)st.st_size)
536                 return 0;
537
538         if (len < (uint64_t)st.st_size) {
539                 /* Shrink - use ftruncate. */
540
541                 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
542                                 fsp->fsp_name, (double)st.st_size ));
543
544                 flush_write_cache(fsp, SIZECHANGE_FLUSH);
545                 if ((ret = SMB_VFS_FTRUNCATE(fsp, (SMB_OFF_T)len)) != -1) {
546                         set_filelen_write_cache(fsp, len);
547                 }
548                 return ret;
549         }
550
551         /* Grow - we need to test if we have enough space. */
552
553         if (!lp_strict_allocate(SNUM(fsp->conn)))
554                 return 0;
555
556         len -= st.st_size;
557         len /= 1024; /* Len is now number of 1k blocks needed. */
558         space_avail = get_dfree_info(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
559         if (space_avail == (uint64_t)-1) {
560                 return -1;
561         }
562
563         DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
564                         fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
565
566         if (len > space_avail) {
567                 errno = ENOSPC;
568                 return -1;
569         }
570
571         return 0;
572 }
573
574 /****************************************************************************
575  A vfs set_filelen call.
576  set the length of a file from a filedescriptor.
577  Returns 0 on success, -1 on failure.
578 ****************************************************************************/
579
580 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
581 {
582         int ret;
583
584         release_level_2_oplocks_on_change(fsp);
585         DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
586         flush_write_cache(fsp, SIZECHANGE_FLUSH);
587         if ((ret = SMB_VFS_FTRUNCATE(fsp, len)) != -1) {
588                 set_filelen_write_cache(fsp, len);
589                 notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
590                              FILE_NOTIFY_CHANGE_SIZE
591                              | FILE_NOTIFY_CHANGE_ATTRIBUTES,
592                              fsp->fsp_name);
593         }
594
595         return ret;
596 }
597
598 /****************************************************************************
599  A vfs fill sparse call.
600  Writes zeros from the end of file to len, if len is greater than EOF.
601  Used only by strict_sync.
602  Returns 0 on success, -1 on failure.
603 ****************************************************************************/
604
605 #define SPARSE_BUF_WRITE_SIZE (32*1024)
606
607 int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
608 {
609         int ret;
610         SMB_STRUCT_STAT st;
611         SMB_OFF_T offset;
612         size_t total;
613         size_t num_to_write;
614         ssize_t pwrite_ret;
615
616         release_level_2_oplocks_on_change(fsp);
617         ret = SMB_VFS_FSTAT(fsp, &st);
618         if (ret == -1) {
619                 return ret;
620         }
621
622         if (len <= st.st_size) {
623                 return 0;
624         }
625
626         DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to len %.0f (%.0f bytes)\n",
627                 fsp->fsp_name, (double)st.st_size, (double)len, (double)(len - st.st_size)));
628
629         flush_write_cache(fsp, SIZECHANGE_FLUSH);
630
631         if (!sparse_buf) {
632                 sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE);
633                 if (!sparse_buf) {
634                         errno = ENOMEM;
635                         return -1;
636                 }
637         }
638
639         offset = st.st_size;
640         num_to_write = len - st.st_size;
641         total = 0;
642
643         while (total < num_to_write) {
644                 size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (num_to_write - total));
645
646                 pwrite_ret = SMB_VFS_PWRITE(fsp, sparse_buf, curr_write_size, offset + total);
647                 if (pwrite_ret == -1) {
648                         DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s\n",
649                                 fsp->fsp_name, strerror(errno) ));
650                         return -1;
651                 }
652                 if (pwrite_ret == 0) {
653                         return 0;
654                 }
655
656                 total += pwrite_ret;
657         }
658
659         set_filelen_write_cache(fsp, len);
660         return 0;
661 }
662
663 /****************************************************************************
664  Transfer some data (n bytes) between two file_struct's.
665 ****************************************************************************/
666
667 static ssize_t vfs_read_fn(void *file, void *buf, size_t len)
668 {
669         struct files_struct *fsp = (struct files_struct *)file;
670
671         return SMB_VFS_READ(fsp, buf, len);
672 }
673
674 static ssize_t vfs_write_fn(void *file, const void *buf, size_t len)
675 {
676         struct files_struct *fsp = (struct files_struct *)file;
677
678         return SMB_VFS_WRITE(fsp, buf, len);
679 }
680
681 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
682 {
683         return transfer_file_internal((void *)in, (void *)out, n,
684                                       vfs_read_fn, vfs_write_fn);
685 }
686
687 /*******************************************************************
688  A vfs_readdir wrapper which just returns the file name.
689 ********************************************************************/
690
691 char *vfs_readdirname(connection_struct *conn, void *p)
692 {
693         SMB_STRUCT_DIRENT *ptr= NULL;
694         char *dname;
695
696         if (!p)
697                 return(NULL);
698
699         ptr = SMB_VFS_READDIR(conn, (DIR *)p);
700         if (!ptr)
701                 return(NULL);
702
703         dname = ptr->d_name;
704
705 #ifdef NEXT2
706         if (telldir(p) < 0)
707                 return(NULL);
708 #endif
709
710 #ifdef HAVE_BROKEN_READDIR_NAME
711         /* using /usr/ucb/cc is BAD */
712         dname = dname - 2;
713 #endif
714
715         return(dname);
716 }
717
718 /*******************************************************************
719  A wrapper for vfs_chdir().
720 ********************************************************************/
721
722 int vfs_ChDir(connection_struct *conn, const char *path)
723 {
724         int res;
725
726         if (!LastDir) {
727                 LastDir = SMB_STRDUP("");
728         }
729
730         if (strcsequal(path,"."))
731                 return(0);
732
733         if (*path == '/' && strcsequal(LastDir,path))
734                 return(0);
735
736         DEBUG(4,("vfs_ChDir to %s\n",path));
737
738         res = SMB_VFS_CHDIR(conn,path);
739         if (!res) {
740                 SAFE_FREE(LastDir);
741                 LastDir = SMB_STRDUP(path);
742         }
743         return(res);
744 }
745
746 /*******************************************************************
747  Return the absolute current directory path - given a UNIX pathname.
748  Note that this path is returned in DOS format, not UNIX
749  format. Note this can be called with conn == NULL.
750 ********************************************************************/
751
752 struct getwd_cache_key {
753         SMB_DEV_T dev;
754         SMB_INO_T ino;
755 };
756
757 char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn)
758 {
759         char s[PATH_MAX+1];
760         SMB_STRUCT_STAT st, st2;
761         char *result;
762         DATA_BLOB cache_value;
763         struct getwd_cache_key key;
764
765         *s = 0;
766
767         if (!lp_getwd_cache()) {
768                 goto nocache;
769         }
770
771         SET_STAT_INVALID(st);
772
773         if (SMB_VFS_STAT(conn, ".",&st) == -1) {
774                 /*
775                  * Known to fail for root: the directory may be NFS-mounted
776                  * and exported with root_squash (so has no root access).
777                  */
778                 DEBUG(1,("vfs_GetWd: couldn't stat \".\" error %s "
779                          "(NFS problem ?)\n", strerror(errno) ));
780                 goto nocache;
781         }
782
783         ZERO_STRUCT(key); /* unlikely, but possible padding */
784         key.dev = st.st_dev;
785         key.ino = st.st_ino;
786
787         if (!memcache_lookup(smbd_memcache(), GETWD_CACHE,
788                              data_blob_const(&key, sizeof(key)),
789                              &cache_value)) {
790                 goto nocache;
791         }
792
793         SMB_ASSERT((cache_value.length > 0)
794                    && (cache_value.data[cache_value.length-1] == '\0'));
795
796         if ((SMB_VFS_STAT(conn, (char *)cache_value.data, &st2) == 0)
797             && (st.st_dev == st2.st_dev) && (st.st_ino == st2.st_ino)
798             && (S_ISDIR(st.st_mode))) {
799                 /*
800                  * Ok, we're done
801                  */
802                 result = talloc_strdup(ctx, (char *)cache_value.data);
803                 if (result == NULL) {
804                         errno = ENOMEM;
805                 }
806                 return result;
807         }
808
809  nocache:
810
811         /*
812          * We don't have the information to hand so rely on traditional
813          * methods. The very slow getcwd, which spawns a process on some
814          * systems, or the not quite so bad getwd.
815          */
816
817         if (!SMB_VFS_GETWD(conn,s)) {
818                 DEBUG(0, ("vfs_GetWd: SMB_VFS_GETWD call failed: %s\n",
819                           strerror(errno)));
820                 return NULL;
821         }
822
823         if (lp_getwd_cache() && VALID_STAT(st)) {
824                 ZERO_STRUCT(key); /* unlikely, but possible padding */
825                 key.dev = st.st_dev;
826                 key.ino = st.st_ino;
827
828                 memcache_add(smbd_memcache(), GETWD_CACHE,
829                              data_blob_const(&key, sizeof(key)),
830                              data_blob_const(s, strlen(s)+1));
831         }
832
833         result = talloc_strdup(ctx, s);
834         if (result == NULL) {
835                 errno = ENOMEM;
836         }
837         return result;
838 }
839
840 /*******************************************************************
841  Reduce a file name, removing .. elements and checking that
842  it is below dir in the heirachy. This uses realpath.
843 ********************************************************************/
844
845 NTSTATUS check_reduced_name(connection_struct *conn, const char *fname)
846 {
847 #ifdef REALPATH_TAKES_NULL
848         bool free_resolved_name = True;
849 #else
850         char resolved_name_buf[PATH_MAX+1];
851         bool free_resolved_name = False;
852 #endif
853         char *resolved_name = NULL;
854         size_t con_path_len = strlen(conn->connectpath);
855         char *p = NULL;
856
857         DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
858
859 #ifdef REALPATH_TAKES_NULL
860         resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
861 #else
862         resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
863 #endif
864
865         if (!resolved_name) {
866                 switch (errno) {
867                         case ENOTDIR:
868                                 DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
869                                 return map_nt_error_from_unix(errno);
870                         case ENOENT:
871                         {
872                                 TALLOC_CTX *ctx = talloc_tos();
873                                 char *tmp_fname = NULL;
874                                 char *last_component = NULL;
875                                 /* Last component didn't exist. Remove it and try and canonicalise the directory. */
876
877                                 tmp_fname = talloc_strdup(ctx, fname);
878                                 if (!tmp_fname) {
879                                         return NT_STATUS_NO_MEMORY;
880                                 }
881                                 p = strrchr_m(tmp_fname, '/');
882                                 if (p) {
883                                         *p++ = '\0';
884                                         last_component = p;
885                                 } else {
886                                         last_component = tmp_fname;
887                                         tmp_fname = talloc_strdup(ctx,
888                                                         ".");
889                                         if (!tmp_fname) {
890                                                 return NT_STATUS_NO_MEMORY;
891                                         }
892                                 }
893
894 #ifdef REALPATH_TAKES_NULL
895                                 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
896 #else
897                                 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
898 #endif
899                                 if (!resolved_name) {
900                                         DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
901                                         return map_nt_error_from_unix(errno);
902                                 }
903                                 tmp_fname = talloc_asprintf(ctx,
904                                                 "%s/%s",
905                                                 resolved_name,
906                                                 last_component);
907                                 if (!tmp_fname) {
908                                         return NT_STATUS_NO_MEMORY;
909                                 }
910 #ifdef REALPATH_TAKES_NULL
911                                 SAFE_FREE(resolved_name);
912                                 resolved_name = SMB_STRDUP(tmp_fname);
913                                 if (!resolved_name) {
914                                         DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
915                                         return NT_STATUS_NO_MEMORY;
916                                 }
917 #else
918                                 safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
919                                 resolved_name = resolved_name_buf;
920 #endif
921                                 break;
922                         }
923                         default:
924                                 DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
925                                 return map_nt_error_from_unix(errno);
926                 }
927         }
928
929         DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
930
931         if (*resolved_name != '/') {
932                 DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
933                 if (free_resolved_name) {
934                         SAFE_FREE(resolved_name);
935                 }
936                 return NT_STATUS_OBJECT_NAME_INVALID;
937         }
938
939         /* Check for widelinks allowed. */
940         if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) {
941                 DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
942                 if (free_resolved_name) {
943                         SAFE_FREE(resolved_name);
944                 }
945                 return NT_STATUS_ACCESS_DENIED;
946         }
947
948         /* Check if we are allowing users to follow symlinks */
949         /* Patch from David Clerc <David.Clerc@cui.unige.ch>
950                 University of Geneva */
951
952 #ifdef S_ISLNK
953         if (!lp_symlinks(SNUM(conn))) {
954                 SMB_STRUCT_STAT statbuf;
955                 if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
956                                 (S_ISLNK(statbuf.st_mode)) ) {
957                         if (free_resolved_name) {
958                                 SAFE_FREE(resolved_name);
959                         }
960                         DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
961                         return NT_STATUS_ACCESS_DENIED;
962                 }
963         }
964 #endif
965
966         DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name));
967         if (free_resolved_name) {
968                 SAFE_FREE(resolved_name);
969         }
970         return NT_STATUS_OK;
971 }