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