Add new parameter, "min receivefile size" (by default set
[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                 req->unread_bytes = 0;
432                 return SMB_VFS_RECVFILE(smbd_server_fd(),
433                                         fsp,
434                                         fsp->fh->fd,
435                                         (SMB_OFF_T)-1,
436                                         N);
437         }
438
439         while (total < N) {
440                 ret = SMB_VFS_WRITE(fsp,fsp->fh->fd,buffer + total,N - total);
441
442                 if (ret == -1)
443                         return -1;
444                 if (ret == 0)
445                         return total;
446
447                 total += ret;
448         }
449         return (ssize_t)total;
450 }
451
452 ssize_t vfs_pwrite_data(struct smb_request *req,
453                         files_struct *fsp,
454                         const char *buffer,
455                         size_t N,
456                         SMB_OFF_T offset)
457 {
458         size_t total=0;
459         ssize_t ret;
460
461         if (req && req->unread_bytes) {
462                 SMB_ASSERT(req->unread_bytes == N);
463                 req->unread_bytes = 0;
464                 return SMB_VFS_RECVFILE(smbd_server_fd(),
465                                         fsp,
466                                         fsp->fh->fd,
467                                         offset,
468                                         N);
469         }
470
471         while (total < N) {
472                 ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, buffer + total,
473                                 N - total, offset + total);
474
475                 if (ret == -1)
476                         return -1;
477                 if (ret == 0)
478                         return total;
479
480                 total += ret;
481         }
482         return (ssize_t)total;
483 }
484 /****************************************************************************
485  An allocate file space call using the vfs interface.
486  Allocates space for a file from a filedescriptor.
487  Returns 0 on success, -1 on failure.
488 ****************************************************************************/
489
490 int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
491 {
492         int ret;
493         SMB_STRUCT_STAT st;
494         connection_struct *conn = fsp->conn;
495         SMB_BIG_UINT space_avail;
496         SMB_BIG_UINT bsize,dfree,dsize;
497
498         release_level_2_oplocks_on_change(fsp);
499
500         /*
501          * Actually try and commit the space on disk....
502          */
503
504         DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
505
506         if (((SMB_OFF_T)len) < 0) {
507                 DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
508                 errno = EINVAL;
509                 return -1;
510         }
511
512         ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
513         if (ret == -1)
514                 return ret;
515
516         if (len == (SMB_BIG_UINT)st.st_size)
517                 return 0;
518
519         if (len < (SMB_BIG_UINT)st.st_size) {
520                 /* Shrink - use ftruncate. */
521
522                 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
523                                 fsp->fsp_name, (double)st.st_size ));
524
525                 flush_write_cache(fsp, SIZECHANGE_FLUSH);
526                 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, (SMB_OFF_T)len)) != -1) {
527                         set_filelen_write_cache(fsp, len);
528                 }
529                 return ret;
530         }
531
532         /* Grow - we need to test if we have enough space. */
533
534         if (!lp_strict_allocate(SNUM(fsp->conn)))
535                 return 0;
536
537         len -= st.st_size;
538         len /= 1024; /* Len is now number of 1k blocks needed. */
539         space_avail = get_dfree_info(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
540         if (space_avail == (SMB_BIG_UINT)-1) {
541                 return -1;
542         }
543
544         DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
545                         fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
546
547         if (len > space_avail) {
548                 errno = ENOSPC;
549                 return -1;
550         }
551
552         return 0;
553 }
554
555 /****************************************************************************
556  A vfs set_filelen call.
557  set the length of a file from a filedescriptor.
558  Returns 0 on success, -1 on failure.
559 ****************************************************************************/
560
561 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
562 {
563         int ret;
564
565         release_level_2_oplocks_on_change(fsp);
566         DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
567         flush_write_cache(fsp, SIZECHANGE_FLUSH);
568         if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, len)) != -1) {
569                 set_filelen_write_cache(fsp, len);
570                 notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
571                              FILE_NOTIFY_CHANGE_SIZE
572                              | FILE_NOTIFY_CHANGE_ATTRIBUTES,
573                              fsp->fsp_name);
574         }
575
576         return ret;
577 }
578
579 /****************************************************************************
580  A vfs fill sparse call.
581  Writes zeros from the end of file to len, if len is greater than EOF.
582  Used only by strict_sync.
583  Returns 0 on success, -1 on failure.
584 ****************************************************************************/
585
586 static char *sparse_buf;
587 #define SPARSE_BUF_WRITE_SIZE (32*1024)
588
589 int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
590 {
591         int ret;
592         SMB_STRUCT_STAT st;
593         SMB_OFF_T offset;
594         size_t total;
595         size_t num_to_write;
596         ssize_t pwrite_ret;
597
598         release_level_2_oplocks_on_change(fsp);
599         ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
600         if (ret == -1) {
601                 return ret;
602         }
603
604         if (len <= st.st_size) {
605                 return 0;
606         }
607
608         DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to len %.0f (%.0f bytes)\n",
609                 fsp->fsp_name, (double)st.st_size, (double)len, (double)(len - st.st_size)));
610
611         flush_write_cache(fsp, SIZECHANGE_FLUSH);
612
613         if (!sparse_buf) {
614                 sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE);
615                 if (!sparse_buf) {
616                         errno = ENOMEM;
617                         return -1;
618                 }
619         }
620
621         offset = st.st_size;
622         num_to_write = len - st.st_size;
623         total = 0;
624
625         while (total < num_to_write) {
626                 size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (num_to_write - total));
627
628                 pwrite_ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, sparse_buf, curr_write_size, offset + total);
629                 if (pwrite_ret == -1) {
630                         DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s\n",
631                                 fsp->fsp_name, strerror(errno) ));
632                         return -1;
633                 }
634                 if (pwrite_ret == 0) {
635                         return 0;
636                 }
637
638                 total += pwrite_ret;
639         }
640
641         set_filelen_write_cache(fsp, len);
642         return 0;
643 }
644
645 /****************************************************************************
646  Transfer some data (n bytes) between two file_struct's.
647 ****************************************************************************/
648
649 static files_struct *in_fsp;
650 static files_struct *out_fsp;
651
652 static ssize_t read_fn(int fd, void *buf, size_t len)
653 {
654         return SMB_VFS_READ(in_fsp, fd, buf, len);
655 }
656
657 static ssize_t write_fn(int fd, const void *buf, size_t len)
658 {
659         return SMB_VFS_WRITE(out_fsp, fd, buf, len);
660 }
661
662 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
663 {
664         in_fsp = in;
665         out_fsp = out;
666
667         return transfer_file_internal(in_fsp->fh->fd, out_fsp->fh->fd, n, read_fn, write_fn);
668 }
669
670 /*******************************************************************
671  A vfs_readdir wrapper which just returns the file name.
672 ********************************************************************/
673
674 char *vfs_readdirname(connection_struct *conn, void *p)
675 {
676         SMB_STRUCT_DIRENT *ptr= NULL;
677         char *dname;
678
679         if (!p)
680                 return(NULL);
681
682         ptr = SMB_VFS_READDIR(conn, (DIR *)p);
683         if (!ptr)
684                 return(NULL);
685
686         dname = ptr->d_name;
687
688 #ifdef NEXT2
689         if (telldir(p) < 0)
690                 return(NULL);
691 #endif
692
693 #ifdef HAVE_BROKEN_READDIR_NAME
694         /* using /usr/ucb/cc is BAD */
695         dname = dname - 2;
696 #endif
697
698         return(dname);
699 }
700
701 /*******************************************************************
702  A wrapper for vfs_chdir().
703 ********************************************************************/
704
705 int vfs_ChDir(connection_struct *conn, const char *path)
706 {
707         int res;
708         static char *LastDir = NULL;
709
710         if (!LastDir) {
711                 LastDir = SMB_STRDUP("");
712         }
713
714         if (strcsequal(path,"."))
715                 return(0);
716
717         if (*path == '/' && strcsequal(LastDir,path))
718                 return(0);
719
720         DEBUG(4,("vfs_ChDir to %s\n",path));
721
722         res = SMB_VFS_CHDIR(conn,path);
723         if (!res) {
724                 SAFE_FREE(LastDir);
725                 LastDir = SMB_STRDUP(path);
726         }
727         return(res);
728 }
729
730 /* number of list structures for a caching GetWd function. */
731 #define MAX_GETWDCACHE (50)
732
733 static struct {
734         SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
735         SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
736         char *path; /* The pathname. */
737         bool valid;
738 } ino_list[MAX_GETWDCACHE];
739
740 extern bool use_getwd_cache;
741
742 /****************************************************************************
743  Prompte a ptr (to make it recently used)
744 ****************************************************************************/
745
746 static void array_promote(char *array,int elsize,int element)
747 {
748         char *p;
749         if (element == 0)
750                 return;
751
752         p = (char *)SMB_MALLOC(elsize);
753
754         if (!p) {
755                 DEBUG(5,("array_promote: malloc fail\n"));
756                 return;
757         }
758
759         memcpy(p,array + element * elsize, elsize);
760         memmove(array + elsize,array,elsize*element);
761         memcpy(array,p,elsize);
762         SAFE_FREE(p);
763 }
764
765 /*******************************************************************
766  Return the absolute current directory path - given a UNIX pathname.
767  Note that this path is returned in DOS format, not UNIX
768  format. Note this can be called with conn == NULL.
769 ********************************************************************/
770
771 char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn)
772 {
773 #ifdef PATH_MAX
774         char s[PATH_MAX+1];
775 #else
776         pstring s;
777 #endif
778         static bool getwd_cache_init = False;
779         SMB_STRUCT_STAT st, st2;
780         int i;
781         char *ret = NULL;
782
783         *s = 0;
784
785         if (!use_getwd_cache) {
786  nocache:
787                 ret = SMB_VFS_GETWD(conn,s);
788                 if (!ret) {
789                         DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, "
790                                 "errno %s\n",strerror(errno)));
791                         return NULL;
792                 }
793                 return talloc_strdup(ctx, ret);
794         }
795
796         /* init the cache */
797         if (!getwd_cache_init) {
798                 getwd_cache_init = True;
799                 for (i=0;i<MAX_GETWDCACHE;i++) {
800                         string_set(&ino_list[i].path,"");
801                         ino_list[i].valid = False;
802                 }
803         }
804
805         /*  Get the inode of the current directory, if this doesn't work we're
806                 in trouble :-) */
807
808         if (SMB_VFS_STAT(conn, ".",&st) == -1) {
809                 /* Known to fail for root: the directory may be
810                  * NFS-mounted and exported with root_squash (so has no root access). */
811                 DEBUG(1,("vfs_GetWd: couldn't stat \".\" error %s "
812                         "(NFS problem ?)\n",
813                         strerror(errno) ));
814                 goto nocache;
815         }
816
817
818         for (i=0; i<MAX_GETWDCACHE; i++) {
819                 if (ino_list[i].valid) {
820
821                         /*  If we have found an entry with a matching inode and dev number
822                                 then find the inode number for the directory in the cached string.
823                                 If this agrees with that returned by the stat for the current
824                                 directory then all is o.k. (but make sure it is a directory all
825                                 the same...) */
826
827                         if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
828                                 if (SMB_VFS_STAT(conn,ino_list[i].path,&st2) == 0) {
829                                         if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
830                                                         (st2.st_mode & S_IFMT) == S_IFDIR) {
831
832                                                 ret = talloc_strdup(ctx,
833                                                         ino_list[i].path);
834
835                                                 /* promote it for future use */
836                                                 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
837                                                 if (ret == NULL) {
838                                                         errno = ENOMEM;
839                                                 }
840                                                 return ret;
841                                         } else {
842                                                 /*  If the inode is different then something's changed,
843                                                         scrub the entry and start from scratch. */
844                                                 ino_list[i].valid = False;
845                                         }
846                                 }
847                         }
848                 }
849         }
850
851         /*  We don't have the information to hand so rely on traditional
852          *  methods. The very slow getcwd, which spawns a process on some
853          *  systems, or the not quite so bad getwd. */
854
855         if (!SMB_VFS_GETWD(conn,s)) {
856                 DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",
857                                 strerror(errno)));
858                 return (NULL);
859         }
860
861         ret = talloc_strdup(ctx,s);
862
863         DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",
864                                 s,(double)st.st_ino,(double)st.st_dev));
865
866         /* add it to the cache */
867         i = MAX_GETWDCACHE - 1;
868         string_set(&ino_list[i].path,s);
869         ino_list[i].dev = st.st_dev;
870         ino_list[i].inode = st.st_ino;
871         ino_list[i].valid = True;
872
873         /* put it at the top of the list */
874         array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
875
876         if (ret == NULL) {
877                 errno = ENOMEM;
878         }
879         return ret;
880 }
881
882 /*******************************************************************
883  Reduce a file name, removing .. elements and checking that
884  it is below dir in the heirachy. This uses realpath.
885 ********************************************************************/
886
887 NTSTATUS check_reduced_name(connection_struct *conn, const char *fname)
888 {
889 #ifdef REALPATH_TAKES_NULL
890         bool free_resolved_name = True;
891 #else
892 #ifdef PATH_MAX
893         char resolved_name_buf[PATH_MAX+1];
894 #else
895         pstring resolved_name_buf;
896 #endif
897         bool free_resolved_name = False;
898 #endif
899         char *resolved_name = NULL;
900         size_t con_path_len = strlen(conn->connectpath);
901         char *p = NULL;
902
903         DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
904
905 #ifdef REALPATH_TAKES_NULL
906         resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
907 #else
908         resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
909 #endif
910
911         if (!resolved_name) {
912                 switch (errno) {
913                         case ENOTDIR:
914                                 DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
915                                 return map_nt_error_from_unix(errno);
916                         case ENOENT:
917                         {
918                                 TALLOC_CTX *tmp_ctx = talloc_stackframe();
919                                 char *tmp_fname = NULL;
920                                 char *last_component = NULL;
921                                 /* Last component didn't exist. Remove it and try and canonicalise the directory. */
922
923                                 tmp_fname = talloc_strdup(tmp_ctx, fname);
924                                 if (!tmp_fname) {
925                                         TALLOC_FREE(tmp_ctx);
926                                         return NT_STATUS_NO_MEMORY;
927                                 }
928                                 p = strrchr_m(tmp_fname, '/');
929                                 if (p) {
930                                         *p++ = '\0';
931                                         last_component = p;
932                                 } else {
933                                         last_component = tmp_fname;
934                                         tmp_fname = talloc_strdup(tmp_ctx,
935                                                         ".");
936                                         if (!tmp_fname) {
937                                                 TALLOC_FREE(tmp_ctx);
938                                                 return NT_STATUS_NO_MEMORY;
939                                         }
940                                 }
941
942 #ifdef REALPATH_TAKES_NULL
943                                 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
944 #else
945                                 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
946 #endif
947                                 if (!resolved_name) {
948                                         DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
949                                         TALLOC_FREE(tmp_ctx);
950                                         return map_nt_error_from_unix(errno);
951                                 }
952                                 tmp_fname = talloc_asprintf(tmp_ctx,
953                                                 "%s/%s",
954                                                 resolved_name,
955                                                 last_component);
956                                 if (!tmp_fname) {
957                                         TALLOC_FREE(tmp_ctx);
958                                         return NT_STATUS_NO_MEMORY;
959                                 }
960 #ifdef REALPATH_TAKES_NULL
961                                 SAFE_FREE(resolved_name);
962                                 resolved_name = SMB_STRDUP(tmp_fname);
963                                 if (!resolved_name) {
964                                         DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
965                                         return NT_STATUS_NO_MEMORY;
966                                 }
967 #else
968 #ifdef PATH_MAX
969                                 safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
970 #else
971                                 pstrcpy(resolved_name_buf, tmp_fname);
972 #endif
973                                 resolved_name = resolved_name_buf;
974 #endif
975                                 TALLOC_FREE(tmp_ctx);
976                                 break;
977                         }
978                         default:
979                                 DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
980                                 return map_nt_error_from_unix(errno);
981                 }
982         }
983
984         DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
985
986         if (*resolved_name != '/') {
987                 DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
988                 if (free_resolved_name) {
989                         SAFE_FREE(resolved_name);
990                 }
991                 return NT_STATUS_OBJECT_NAME_INVALID;
992         }
993
994         /* Check for widelinks allowed. */
995         if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) {
996                 DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
997                 if (free_resolved_name) {
998                         SAFE_FREE(resolved_name);
999                 }
1000                 return NT_STATUS_ACCESS_DENIED;
1001         }
1002
1003         /* Check if we are allowing users to follow symlinks */
1004         /* Patch from David Clerc <David.Clerc@cui.unige.ch>
1005                 University of Geneva */
1006
1007 #ifdef S_ISLNK
1008         if (!lp_symlinks(SNUM(conn))) {
1009                 SMB_STRUCT_STAT statbuf;
1010                 if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
1011                                 (S_ISLNK(statbuf.st_mode)) ) {
1012                         if (free_resolved_name) {
1013                                 SAFE_FREE(resolved_name);
1014                         }
1015                         DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
1016                         return NT_STATUS_ACCESS_DENIED;
1017                 }
1018         }
1019 #endif
1020
1021         DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name));
1022         if (free_resolved_name) {
1023                 SAFE_FREE(resolved_name);
1024         }
1025         return NT_STATUS_OK;
1026 }