Another typo, sorry for samba-cvs spam :-)
[Samba/gebeck_regimport.git] / source / smbd / vfs.c
blob2f981c743f277044abcd1ecfea05a7c0ea6a9cba
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
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 This work was sponsored by Optifacio Software Services, Inc.
25 #include "includes.h"
27 #undef DBGC_CLASS
28 #define DBGC_CLASS DBGC_VFS
30 struct vfs_init_function_entry {
31 char *name;
32 vfs_op_tuple *vfs_op_tuples;
33 struct vfs_init_function_entry *prev, *next;
36 static struct vfs_init_function_entry *backends = NULL;
38 /* Some structures to help us initialise the vfs operations table */
40 struct vfs_syminfo {
41 char *name;
42 void *fptr;
45 /* Default vfs hooks. WARNING: The order of these initialisers is
46 very important. They must be in the same order as defined in
47 vfs.h. Change at your own peril. */
49 static struct vfs_ops default_vfs = {
52 /* Disk operations */
54 vfswrap_dummy_connect,
55 vfswrap_dummy_disconnect,
56 vfswrap_disk_free,
57 vfswrap_get_quota,
58 vfswrap_set_quota,
59 vfswrap_get_shadow_copy_data,
61 /* Directory operations */
63 vfswrap_opendir,
64 vfswrap_readdir,
65 vfswrap_mkdir,
66 vfswrap_rmdir,
67 vfswrap_closedir,
69 /* File operations */
71 vfswrap_open,
72 vfswrap_close,
73 vfswrap_read,
74 vfswrap_pread,
75 vfswrap_write,
76 vfswrap_pwrite,
77 vfswrap_lseek,
78 vfswrap_sendfile,
79 vfswrap_rename,
80 vfswrap_fsync,
81 vfswrap_stat,
82 vfswrap_fstat,
83 vfswrap_lstat,
84 vfswrap_unlink,
85 vfswrap_chmod,
86 vfswrap_fchmod,
87 vfswrap_chown,
88 vfswrap_fchown,
89 vfswrap_chdir,
90 vfswrap_getwd,
91 vfswrap_utime,
92 vfswrap_ftruncate,
93 vfswrap_lock,
94 vfswrap_symlink,
95 vfswrap_readlink,
96 vfswrap_link,
97 vfswrap_mknod,
98 vfswrap_realpath,
100 /* Windows ACL operations. */
101 vfswrap_fget_nt_acl,
102 vfswrap_get_nt_acl,
103 vfswrap_fset_nt_acl,
104 vfswrap_set_nt_acl,
106 /* POSIX ACL operations. */
107 vfswrap_chmod_acl,
108 vfswrap_fchmod_acl,
110 vfswrap_sys_acl_get_entry,
111 vfswrap_sys_acl_get_tag_type,
112 vfswrap_sys_acl_get_permset,
113 vfswrap_sys_acl_get_qualifier,
114 vfswrap_sys_acl_get_file,
115 vfswrap_sys_acl_get_fd,
116 vfswrap_sys_acl_clear_perms,
117 vfswrap_sys_acl_add_perm,
118 vfswrap_sys_acl_to_text,
119 vfswrap_sys_acl_init,
120 vfswrap_sys_acl_create_entry,
121 vfswrap_sys_acl_set_tag_type,
122 vfswrap_sys_acl_set_qualifier,
123 vfswrap_sys_acl_set_permset,
124 vfswrap_sys_acl_valid,
125 vfswrap_sys_acl_set_file,
126 vfswrap_sys_acl_set_fd,
127 vfswrap_sys_acl_delete_def_file,
128 vfswrap_sys_acl_get_perm,
129 vfswrap_sys_acl_free_text,
130 vfswrap_sys_acl_free_acl,
131 vfswrap_sys_acl_free_qualifier,
133 /* EA operations. */
134 vfswrap_getxattr,
135 vfswrap_lgetxattr,
136 vfswrap_fgetxattr,
137 vfswrap_listxattr,
138 vfswrap_llistxattr,
139 vfswrap_flistxattr,
140 vfswrap_removexattr,
141 vfswrap_lremovexattr,
142 vfswrap_fremovexattr,
143 vfswrap_setxattr,
144 vfswrap_lsetxattr,
145 vfswrap_fsetxattr
149 /****************************************************************************
150 maintain the list of available backends
151 ****************************************************************************/
153 static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name)
155 struct vfs_init_function_entry *entry = backends;
157 while(entry) {
158 if (strcmp(entry->name, name)==0) return entry;
159 entry = entry->next;
162 return NULL;
165 NTSTATUS smb_register_vfs(int version, const char *name, vfs_op_tuple *vfs_op_tuples)
167 struct vfs_init_function_entry *entry = backends;
169 if ((version != SMB_VFS_INTERFACE_VERSION)) {
170 DEBUG(0, ("Failed to register vfs module.\n"
171 "The module was compiled against SMB_VFS_INTERFACE_VERSION %d,\n"
172 "current SMB_VFS_INTERFACE_VERSION is %d.\n"
173 "Please recompile against the current Samba Version!\n",
174 version, SMB_VFS_INTERFACE_VERSION));
175 return NT_STATUS_OBJECT_TYPE_MISMATCH;
178 if (!name || !name[0] || !vfs_op_tuples) {
179 DEBUG(0,("smb_register_vfs() called with NULL pointer or empty name!\n"));
180 return NT_STATUS_INVALID_PARAMETER;
183 if (vfs_find_backend_entry(name)) {
184 DEBUG(0,("VFS module %s already loaded!\n", name));
185 return NT_STATUS_OBJECT_NAME_COLLISION;
188 entry = smb_xmalloc(sizeof(struct vfs_init_function_entry));
189 entry->name = smb_xstrdup(name);
190 entry->vfs_op_tuples = vfs_op_tuples;
192 DLIST_ADD(backends, entry);
193 DEBUG(5, ("Successfully added vfs backend '%s'\n", name));
194 return NT_STATUS_OK;
197 /****************************************************************************
198 initialise default vfs hooks
199 ****************************************************************************/
201 static void vfs_init_default(connection_struct *conn)
203 DEBUG(3, ("Initialising default vfs hooks\n"));
205 memcpy(&conn->vfs.ops, &default_vfs.ops, sizeof(default_vfs.ops));
206 memcpy(&conn->vfs_opaque.ops, &default_vfs.ops, sizeof(default_vfs.ops));
209 /****************************************************************************
210 initialise custom vfs hooks
211 ****************************************************************************/
213 BOOL vfs_init_custom(connection_struct *conn, const char *vfs_object)
215 vfs_op_tuple *ops;
216 char *module_name = NULL;
217 char *module_param = NULL, *p;
218 int i;
219 vfs_handle_struct *handle;
220 struct vfs_init_function_entry *entry;
222 if (!conn||!vfs_object||!vfs_object[0]) {
223 DEBUG(0,("vfs_init_custon() called with NULL pointer or emtpy vfs_object!\n"));
224 return False;
227 if(!backends) static_init_vfs;
229 DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object));
231 module_name = smb_xstrdup(vfs_object);
233 p = strchr(module_name, ':');
235 if (p) {
236 *p = 0;
237 module_param = p+1;
238 trim_char(module_param, ' ', ' ');
241 trim_char(module_name, ' ', ' ');
243 /* First, try to load the module with the new module system */
244 if((entry = vfs_find_backend_entry(module_name)) ||
245 (NT_STATUS_IS_OK(smb_probe_module("vfs", module_name)) &&
246 (entry = vfs_find_backend_entry(module_name)))) {
248 DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
250 if ((ops = entry->vfs_op_tuples) == NULL) {
251 DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object));
252 SAFE_FREE(module_name);
253 return False;
255 } else {
256 DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
257 SAFE_FREE(module_name);
258 return False;
261 handle = (vfs_handle_struct *)talloc_zero(conn->mem_ctx,sizeof(vfs_handle_struct));
262 if (!handle) {
263 DEBUG(0,("talloc_zero() failed!\n"));
264 SAFE_FREE(module_name);
265 return False;
267 memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops));
268 handle->conn = conn;
269 if (module_param) {
270 handle->param = talloc_strdup(conn->mem_ctx, module_param);
272 DLIST_ADD(conn->vfs_handles, handle);
274 for(i=0; ops[i].op != NULL; i++) {
275 DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer));
276 if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) {
277 /* Check whether this operation was already made opaque by different module */
278 if(((void**)&conn->vfs_opaque.ops)[ops[i].type] == ((void**)&default_vfs.ops)[ops[i].type]) {
279 /* No, it isn't overloaded yet. Overload. */
280 DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object));
281 ((void**)&conn->vfs_opaque.ops)[ops[i].type] = ops[i].op;
282 ((vfs_handle_struct **)&conn->vfs_opaque.handles)[ops[i].type] = handle;
285 /* Change current VFS disposition*/
286 DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object));
287 ((void**)&conn->vfs.ops)[ops[i].type] = ops[i].op;
288 ((vfs_handle_struct **)&conn->vfs.handles)[ops[i].type] = handle;
291 SAFE_FREE(module_name);
292 return True;
295 /*****************************************************************
296 Generic VFS init.
297 ******************************************************************/
299 BOOL smbd_vfs_init(connection_struct *conn)
301 const char **vfs_objects;
302 unsigned int i = 0;
303 int j = 0;
305 /* Normal share - initialise with disk access functions */
306 vfs_init_default(conn);
307 vfs_objects = lp_vfs_objects(SNUM(conn));
309 /* Override VFS functions if 'vfs object' was not specified*/
310 if (!vfs_objects || !vfs_objects[0])
311 return True;
313 for (i=0; vfs_objects[i] ;) {
314 i++;
317 for (j=i-1; j >= 0; j--) {
318 if (!vfs_init_custom(conn, vfs_objects[j])) {
319 DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects[j]));
320 return False;
323 return True;
326 /*******************************************************************
327 Check if directory exists.
328 ********************************************************************/
330 BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
332 SMB_STRUCT_STAT st2;
333 BOOL ret;
335 if (!st)
336 st = &st2;
338 if (SMB_VFS_STAT(conn,dname,st) != 0)
339 return(False);
341 ret = S_ISDIR(st->st_mode);
342 if(!ret)
343 errno = ENOTDIR;
345 return ret;
348 /*******************************************************************
349 vfs mkdir wrapper
350 ********************************************************************/
352 int vfs_MkDir(connection_struct *conn, const char *name, mode_t mode)
354 int ret;
355 SMB_STRUCT_STAT sbuf;
357 if(!(ret=SMB_VFS_MKDIR(conn, name, mode))) {
359 inherit_access_acl(conn, name, mode);
362 * Check if high bits should have been set,
363 * then (if bits are missing): add them.
364 * Consider bits automagically set by UNIX, i.e. SGID bit from parent dir.
366 if(mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) &&
367 !SMB_VFS_STAT(conn,name,&sbuf) && (mode & ~sbuf.st_mode))
368 SMB_VFS_CHMOD(conn,name,sbuf.st_mode | (mode & ~sbuf.st_mode));
370 return ret;
373 /*******************************************************************
374 Check if an object exists in the vfs.
375 ********************************************************************/
377 BOOL vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
379 SMB_STRUCT_STAT st;
381 if (!sbuf)
382 sbuf = &st;
384 ZERO_STRUCTP(sbuf);
386 if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
387 return(False);
388 return True;
391 /*******************************************************************
392 Check if a file exists in the vfs.
393 ********************************************************************/
395 BOOL vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
397 SMB_STRUCT_STAT st;
399 if (!sbuf)
400 sbuf = &st;
402 ZERO_STRUCTP(sbuf);
404 if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
405 return False;
406 return(S_ISREG(sbuf->st_mode));
409 /****************************************************************************
410 Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
411 ****************************************************************************/
413 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
415 size_t total=0;
417 while (total < byte_count)
419 ssize_t ret = SMB_VFS_READ(fsp, fsp->fd, buf + total,
420 byte_count - total);
422 if (ret == 0) return total;
423 if (ret == -1) {
424 if (errno == EINTR)
425 continue;
426 else
427 return -1;
429 total += ret;
431 return (ssize_t)total;
434 ssize_t vfs_pread_data(files_struct *fsp, char *buf,
435 size_t byte_count, SMB_OFF_T offset)
437 size_t total=0;
439 while (total < byte_count)
441 ssize_t ret = SMB_VFS_PREAD(fsp, fsp->fd, buf + total,
442 byte_count - total, offset + total);
444 if (ret == 0) return total;
445 if (ret == -1) {
446 if (errno == EINTR)
447 continue;
448 else
449 return -1;
451 total += ret;
453 return (ssize_t)total;
456 /****************************************************************************
457 Write data to a fd on the vfs.
458 ****************************************************************************/
460 ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N)
462 size_t total=0;
463 ssize_t ret;
465 while (total < N) {
466 ret = SMB_VFS_WRITE(fsp,fsp->fd,buffer + total,N - total);
468 if (ret == -1)
469 return -1;
470 if (ret == 0)
471 return total;
473 total += ret;
475 return (ssize_t)total;
478 ssize_t vfs_pwrite_data(files_struct *fsp,const char *buffer,
479 size_t N, SMB_OFF_T offset)
481 size_t total=0;
482 ssize_t ret;
484 while (total < N) {
485 ret = SMB_VFS_PWRITE(fsp, fsp->fd, buffer + total,
486 N - total, offset + total);
488 if (ret == -1)
489 return -1;
490 if (ret == 0)
491 return total;
493 total += ret;
495 return (ssize_t)total;
497 /****************************************************************************
498 An allocate file space call using the vfs interface.
499 Allocates space for a file from a filedescriptor.
500 Returns 0 on success, -1 on failure.
501 ****************************************************************************/
503 int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
505 int ret;
506 SMB_STRUCT_STAT st;
507 connection_struct *conn = fsp->conn;
508 SMB_BIG_UINT space_avail;
509 SMB_BIG_UINT bsize,dfree,dsize;
511 release_level_2_oplocks_on_change(fsp);
514 * Actually try and commit the space on disk....
517 DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
519 if (((SMB_OFF_T)len) < 0) {
520 DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
521 return -1;
524 ret = SMB_VFS_FSTAT(fsp,fsp->fd,&st);
525 if (ret == -1)
526 return ret;
528 if (len == (SMB_BIG_UINT)st.st_size)
529 return 0;
531 if (len < (SMB_BIG_UINT)st.st_size) {
532 /* Shrink - use ftruncate. */
534 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
535 fsp->fsp_name, (double)st.st_size ));
537 flush_write_cache(fsp, SIZECHANGE_FLUSH);
538 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fd, (SMB_OFF_T)len)) != -1) {
539 set_filelen_write_cache(fsp, len);
541 return ret;
544 /* Grow - we need to test if we have enough space. */
546 if (!lp_strict_allocate(SNUM(fsp->conn)))
547 return 0;
549 len -= st.st_size;
550 len /= 1024; /* Len is now number of 1k blocks needed. */
551 space_avail = SMB_VFS_DISK_FREE(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
553 DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
554 fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
556 if (len > space_avail) {
557 errno = ENOSPC;
558 return -1;
561 return 0;
564 /****************************************************************************
565 A vfs set_filelen call.
566 set the length of a file from a filedescriptor.
567 Returns 0 on success, -1 on failure.
568 ****************************************************************************/
570 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
572 int ret;
574 release_level_2_oplocks_on_change(fsp);
575 DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
576 flush_write_cache(fsp, SIZECHANGE_FLUSH);
577 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fd, len)) != -1)
578 set_filelen_write_cache(fsp, len);
580 return ret;
583 /****************************************************************************
584 Transfer some data (n bytes) between two file_struct's.
585 ****************************************************************************/
587 static files_struct *in_fsp;
588 static files_struct *out_fsp;
590 static ssize_t read_fn(int fd, void *buf, size_t len)
592 return SMB_VFS_READ(in_fsp, fd, buf, len);
595 static ssize_t write_fn(int fd, const void *buf, size_t len)
597 return SMB_VFS_WRITE(out_fsp, fd, buf, len);
600 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
602 in_fsp = in;
603 out_fsp = out;
605 return transfer_file_internal(in_fsp->fd, out_fsp->fd, n, read_fn, write_fn);
608 /*******************************************************************
609 A vfs_readdir wrapper which just returns the file name.
610 ********************************************************************/
612 char *vfs_readdirname(connection_struct *conn, void *p)
614 struct dirent *ptr= NULL;
615 char *dname;
617 if (!p)
618 return(NULL);
620 ptr = (struct dirent *)SMB_VFS_READDIR(conn,p);
621 if (!ptr)
622 return(NULL);
624 dname = ptr->d_name;
626 #ifdef NEXT2
627 if (telldir(p) < 0)
628 return(NULL);
629 #endif
631 #ifdef HAVE_BROKEN_READDIR
632 /* using /usr/ucb/cc is BAD */
633 dname = dname - 2;
634 #endif
636 return(dname);
639 /*******************************************************************
640 A wrapper for vfs_chdir().
641 ********************************************************************/
643 int vfs_ChDir(connection_struct *conn, const char *path)
645 int res;
646 static pstring LastDir="";
648 if (strcsequal(path,"."))
649 return(0);
651 if (*path == '/' && strcsequal(LastDir,path))
652 return(0);
654 DEBUG(4,("vfs_ChDir to %s\n",path));
656 res = SMB_VFS_CHDIR(conn,path);
657 if (!res)
658 pstrcpy(LastDir,path);
659 return(res);
662 /* number of list structures for a caching GetWd function. */
663 #define MAX_GETWDCACHE (50)
665 static struct {
666 SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
667 SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
668 char *dos_path; /* The pathname in DOS format. */
669 BOOL valid;
670 } ino_list[MAX_GETWDCACHE];
672 extern BOOL use_getwd_cache;
674 /****************************************************************************
675 Prompte a ptr (to make it recently used)
676 ****************************************************************************/
678 static void array_promote(char *array,int elsize,int element)
680 char *p;
681 if (element == 0)
682 return;
684 p = (char *)malloc(elsize);
686 if (!p) {
687 DEBUG(5,("array_promote: malloc fail\n"));
688 return;
691 memcpy(p,array + element * elsize, elsize);
692 memmove(array + elsize,array,elsize*element);
693 memcpy(array,p,elsize);
694 SAFE_FREE(p);
697 /*******************************************************************
698 Return the absolute current directory path - given a UNIX pathname.
699 Note that this path is returned in DOS format, not UNIX
700 format. Note this can be called with conn == NULL.
701 ********************************************************************/
703 char *vfs_GetWd(connection_struct *conn, char *path)
705 pstring s;
706 static BOOL getwd_cache_init = False;
707 SMB_STRUCT_STAT st, st2;
708 int i;
710 *s = 0;
712 if (!use_getwd_cache)
713 return(SMB_VFS_GETWD(conn,path));
715 /* init the cache */
716 if (!getwd_cache_init) {
717 getwd_cache_init = True;
718 for (i=0;i<MAX_GETWDCACHE;i++) {
719 string_set(&ino_list[i].dos_path,"");
720 ino_list[i].valid = False;
724 /* Get the inode of the current directory, if this doesn't work we're
725 in trouble :-) */
727 if (SMB_VFS_STAT(conn, ".",&st) == -1) {
728 DEBUG(0,("Very strange, couldn't stat \".\" path=%s\n", path));
729 return(SMB_VFS_GETWD(conn,path));
733 for (i=0; i<MAX_GETWDCACHE; i++) {
734 if (ino_list[i].valid) {
736 /* If we have found an entry with a matching inode and dev number
737 then find the inode number for the directory in the cached string.
738 If this agrees with that returned by the stat for the current
739 directory then all is o.k. (but make sure it is a directory all
740 the same...) */
742 if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
743 if (SMB_VFS_STAT(conn,ino_list[i].dos_path,&st2) == 0) {
744 if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
745 (st2.st_mode & S_IFMT) == S_IFDIR) {
746 pstrcpy (path, ino_list[i].dos_path);
748 /* promote it for future use */
749 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
750 return (path);
751 } else {
752 /* If the inode is different then something's changed,
753 scrub the entry and start from scratch. */
754 ino_list[i].valid = False;
761 /* We don't have the information to hand so rely on traditional methods.
762 The very slow getcwd, which spawns a process on some systems, or the
763 not quite so bad getwd. */
765 if (!SMB_VFS_GETWD(conn,s)) {
766 DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",strerror(errno)));
767 return (NULL);
770 pstrcpy(path,s);
772 DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
774 /* add it to the cache */
775 i = MAX_GETWDCACHE - 1;
776 string_set(&ino_list[i].dos_path,s);
777 ino_list[i].dev = st.st_dev;
778 ino_list[i].inode = st.st_ino;
779 ino_list[i].valid = True;
781 /* put it at the top of the list */
782 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
784 return (path);
788 /* check if the file 'nmae' is a symlink, in that case check that it point to
789 a file that reside under the 'dir' tree */
791 static BOOL readlink_check(connection_struct *conn, const char *dir, char *name)
793 BOOL ret = True;
794 pstring flink;
795 pstring cleanlink;
796 pstring savedir;
797 pstring realdir;
798 size_t reallen;
800 if (!vfs_GetWd(conn, savedir)) {
801 DEBUG(0,("couldn't vfs_GetWd for %s %s\n", name, dir));
802 return False;
805 if (vfs_ChDir(conn, dir) != 0) {
806 DEBUG(0,("couldn't vfs_ChDir to %s\n", dir));
807 return False;
810 if (!vfs_GetWd(conn, realdir)) {
811 DEBUG(0,("couldn't vfs_GetWd for %s\n", dir));
812 vfs_ChDir(conn, savedir);
813 return(False);
816 reallen = strlen(realdir);
817 if (realdir[reallen -1] == '/') {
818 reallen--;
819 realdir[reallen] = 0;
822 if (SMB_VFS_READLINK(conn, name, flink, sizeof(pstring) -1) != -1) {
823 DEBUG(3,("reduce_name: file path name %s is a symlink\nChecking it's path\n", name));
824 if (*flink == '/') {
825 pstrcpy(cleanlink, flink);
826 } else {
827 pstrcpy(cleanlink, realdir);
828 pstrcat(cleanlink, "/");
829 pstrcat(cleanlink, flink);
831 unix_clean_name(cleanlink);
833 if (strncmp(cleanlink, realdir, reallen) != 0) {
834 DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n", name, realdir, cleanlink, (int)reallen));
835 ret = False;
839 vfs_ChDir(conn, savedir);
841 return ret;
844 /*******************************************************************
845 Reduce a file name, removing .. elements and checking that
846 it is below dir in the heirachy. This uses vfs_GetWd() and so must be run
847 on the system that has the referenced file system.
848 Widelinks are allowed if widelinks is true.
849 ********************************************************************/
851 BOOL reduce_name(connection_struct *conn, pstring s, const char *dir,BOOL widelinks)
853 #ifndef REDUCE_PATHS
854 return True;
855 #else
856 pstring dir2;
857 pstring wd;
858 pstring base_name;
859 pstring newname;
860 char *p=NULL;
861 BOOL relative = (*s != '/');
863 *dir2 = *wd = *base_name = *newname = 0;
865 if (widelinks) {
866 unix_clean_name(s);
867 /* can't have a leading .. */
868 if (strncmp(s,"..",2) == 0 && (s[2]==0 || s[2]=='/')) {
869 DEBUG(3,("Illegal file name? (%s)\n",s));
870 return(False);
873 if (strlen(s) == 0)
874 pstrcpy(s,"./");
876 return(True);
879 DEBUG(3,("reduce_name [%s] [%s]\n",s,dir));
881 /* remove any double slashes */
882 all_string_sub(s,"//","/",0);
884 pstrcpy(base_name,s);
885 p = strrchr_m(base_name,'/');
887 if (!p)
888 return readlink_check(conn, dir, s);
890 if (!vfs_GetWd(conn,wd)) {
891 DEBUG(0,("couldn't vfs_GetWd for %s %s\n",s,dir));
892 return(False);
895 if (vfs_ChDir(conn,dir) != 0) {
896 DEBUG(0,("couldn't vfs_ChDir to %s\n",dir));
897 return(False);
900 if (!vfs_GetWd(conn,dir2)) {
901 DEBUG(0,("couldn't vfs_GetWd for %s\n",dir));
902 vfs_ChDir(conn,wd);
903 return(False);
906 if (p && (p != base_name)) {
907 *p = 0;
908 if (strcmp(p+1,".")==0)
909 p[1]=0;
910 if (strcmp(p+1,"..")==0)
911 *p = '/';
914 if (vfs_ChDir(conn,base_name) != 0) {
915 vfs_ChDir(conn,wd);
916 DEBUG(3,("couldn't vfs_ChDir for %s %s basename=%s\n",s,dir,base_name));
917 return(False);
920 if (!vfs_GetWd(conn,newname)) {
921 vfs_ChDir(conn,wd);
922 DEBUG(2,("couldn't get vfs_GetWd for %s %s\n",s,base_name));
923 return(False);
926 if (p && (p != base_name)) {
927 pstrcat(newname,"/");
928 pstrcat(newname,p+1);
932 size_t l = strlen(dir2);
933 if (dir2[l-1] == '/')
934 l--;
936 if (strncmp(newname,dir2,l) != 0) {
937 vfs_ChDir(conn,wd);
938 DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n",s,dir2,newname,(int)l));
939 return(False);
942 if (!readlink_check(conn, dir, newname)) {
943 DEBUG(2, ("Bad access attemt? %s is a symlink outside the share path", s));
944 return(False);
947 if (relative) {
948 if (newname[l] == '/')
949 pstrcpy(s,newname + l + 1);
950 else
951 pstrcpy(s,newname+l);
952 } else
953 pstrcpy(s,newname);
956 vfs_ChDir(conn,wd);
958 if (strlen(s) == 0)
959 pstrcpy(s,"./");
961 DEBUG(3,("reduced to %s\n",s));
962 return(True);
963 #endif