Always define PATH_MAX. Makes code simpler (removes
[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         char s[PATH_MAX+1];
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         char resolved_name_buf[PATH_MAX+1];
893         bool free_resolved_name = False;
894 #endif
895         char *resolved_name = NULL;
896         size_t con_path_len = strlen(conn->connectpath);
897         char *p = NULL;
898
899         DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
900
901 #ifdef REALPATH_TAKES_NULL
902         resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
903 #else
904         resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
905 #endif
906
907         if (!resolved_name) {
908                 switch (errno) {
909                         case ENOTDIR:
910                                 DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
911                                 return map_nt_error_from_unix(errno);
912                         case ENOENT:
913                         {
914                                 TALLOC_CTX *tmp_ctx = talloc_stackframe();
915                                 char *tmp_fname = NULL;
916                                 char *last_component = NULL;
917                                 /* Last component didn't exist. Remove it and try and canonicalise the directory. */
918
919                                 tmp_fname = talloc_strdup(tmp_ctx, fname);
920                                 if (!tmp_fname) {
921                                         TALLOC_FREE(tmp_ctx);
922                                         return NT_STATUS_NO_MEMORY;
923                                 }
924                                 p = strrchr_m(tmp_fname, '/');
925                                 if (p) {
926                                         *p++ = '\0';
927                                         last_component = p;
928                                 } else {
929                                         last_component = tmp_fname;
930                                         tmp_fname = talloc_strdup(tmp_ctx,
931                                                         ".");
932                                         if (!tmp_fname) {
933                                                 TALLOC_FREE(tmp_ctx);
934                                                 return NT_STATUS_NO_MEMORY;
935                                         }
936                                 }
937
938 #ifdef REALPATH_TAKES_NULL
939                                 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
940 #else
941                                 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
942 #endif
943                                 if (!resolved_name) {
944                                         DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
945                                         TALLOC_FREE(tmp_ctx);
946                                         return map_nt_error_from_unix(errno);
947                                 }
948                                 tmp_fname = talloc_asprintf(tmp_ctx,
949                                                 "%s/%s",
950                                                 resolved_name,
951                                                 last_component);
952                                 if (!tmp_fname) {
953                                         TALLOC_FREE(tmp_ctx);
954                                         return NT_STATUS_NO_MEMORY;
955                                 }
956 #ifdef REALPATH_TAKES_NULL
957                                 SAFE_FREE(resolved_name);
958                                 resolved_name = SMB_STRDUP(tmp_fname);
959                                 if (!resolved_name) {
960                                         DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
961                                         return NT_STATUS_NO_MEMORY;
962                                 }
963 #else
964                                 safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
965                                 resolved_name = resolved_name_buf;
966 #endif
967                                 TALLOC_FREE(tmp_ctx);
968                                 break;
969                         }
970                         default:
971                                 DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
972                                 return map_nt_error_from_unix(errno);
973                 }
974         }
975
976         DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
977
978         if (*resolved_name != '/') {
979                 DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
980                 if (free_resolved_name) {
981                         SAFE_FREE(resolved_name);
982                 }
983                 return NT_STATUS_OBJECT_NAME_INVALID;
984         }
985
986         /* Check for widelinks allowed. */
987         if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) {
988                 DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
989                 if (free_resolved_name) {
990                         SAFE_FREE(resolved_name);
991                 }
992                 return NT_STATUS_ACCESS_DENIED;
993         }
994
995         /* Check if we are allowing users to follow symlinks */
996         /* Patch from David Clerc <David.Clerc@cui.unige.ch>
997                 University of Geneva */
998
999 #ifdef S_ISLNK
1000         if (!lp_symlinks(SNUM(conn))) {
1001                 SMB_STRUCT_STAT statbuf;
1002                 if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
1003                                 (S_ISLNK(statbuf.st_mode)) ) {
1004                         if (free_resolved_name) {
1005                                 SAFE_FREE(resolved_name);
1006                         }
1007                         DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
1008                         return NT_STATUS_ACCESS_DENIED;
1009                 }
1010         }
1011 #endif
1012
1013         DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name));
1014         if (free_resolved_name) {
1015                 SAFE_FREE(resolved_name);
1016         }
1017         return NT_STATUS_OK;
1018 }