sync 3.0 into HEAD for the last time
[Samba.git] / source / smbd / vfs.c
blob753db4cece385e28ec9647c080fdde3ee968ee9f
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_write,
75 vfswrap_lseek,
76 vfswrap_sendfile,
77 vfswrap_rename,
78 vfswrap_fsync,
79 vfswrap_stat,
80 vfswrap_fstat,
81 vfswrap_lstat,
82 vfswrap_unlink,
83 vfswrap_chmod,
84 vfswrap_fchmod,
85 vfswrap_chown,
86 vfswrap_fchown,
87 vfswrap_chdir,
88 vfswrap_getwd,
89 vfswrap_utime,
90 vfswrap_ftruncate,
91 vfswrap_lock,
92 vfswrap_symlink,
93 vfswrap_readlink,
94 vfswrap_link,
95 vfswrap_mknod,
96 vfswrap_realpath,
98 /* Windows ACL operations. */
99 vfswrap_fget_nt_acl,
100 vfswrap_get_nt_acl,
101 vfswrap_fset_nt_acl,
102 vfswrap_set_nt_acl,
104 /* POSIX ACL operations. */
105 vfswrap_chmod_acl,
106 vfswrap_fchmod_acl,
108 vfswrap_sys_acl_get_entry,
109 vfswrap_sys_acl_get_tag_type,
110 vfswrap_sys_acl_get_permset,
111 vfswrap_sys_acl_get_qualifier,
112 vfswrap_sys_acl_get_file,
113 vfswrap_sys_acl_get_fd,
114 vfswrap_sys_acl_clear_perms,
115 vfswrap_sys_acl_add_perm,
116 vfswrap_sys_acl_to_text,
117 vfswrap_sys_acl_init,
118 vfswrap_sys_acl_create_entry,
119 vfswrap_sys_acl_set_tag_type,
120 vfswrap_sys_acl_set_qualifier,
121 vfswrap_sys_acl_set_permset,
122 vfswrap_sys_acl_valid,
123 vfswrap_sys_acl_set_file,
124 vfswrap_sys_acl_set_fd,
125 vfswrap_sys_acl_delete_def_file,
126 vfswrap_sys_acl_get_perm,
127 vfswrap_sys_acl_free_text,
128 vfswrap_sys_acl_free_acl,
129 vfswrap_sys_acl_free_qualifier,
131 /* EA operations. */
132 vfswrap_getxattr,
133 vfswrap_lgetxattr,
134 vfswrap_fgetxattr,
135 vfswrap_listxattr,
136 vfswrap_llistxattr,
137 vfswrap_flistxattr,
138 vfswrap_removexattr,
139 vfswrap_lremovexattr,
140 vfswrap_fremovexattr,
141 vfswrap_setxattr,
142 vfswrap_lsetxattr,
143 vfswrap_fsetxattr
147 /****************************************************************************
148 maintain the list of available backends
149 ****************************************************************************/
151 static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name)
153 struct vfs_init_function_entry *entry = backends;
155 while(entry) {
156 if (strcmp(entry->name, name)==0) return entry;
157 entry = entry->next;
160 return NULL;
163 NTSTATUS smb_register_vfs(int version, const char *name, vfs_op_tuple *vfs_op_tuples)
165 struct vfs_init_function_entry *entry = backends;
167 if ((version != SMB_VFS_INTERFACE_VERSION)) {
168 DEBUG(0, ("Failed to register vfs module.\n"
169 "The module was compiled against SMB_VFS_INTERFACE_VERSION %d,\n"
170 "current SMB_VFS_INTERFACE_VERSION is %d.\n"
171 "Please recompile against the current Samba Version!\n",
172 version, SMB_VFS_INTERFACE_VERSION));
173 return NT_STATUS_OBJECT_TYPE_MISMATCH;
176 if (!name || !name[0] || !vfs_op_tuples) {
177 DEBUG(0,("smb_register_vfs() called with NULL pointer or empty name!\n"));
178 return NT_STATUS_INVALID_PARAMETER;
181 if (vfs_find_backend_entry(name)) {
182 DEBUG(0,("VFS module %s already loaded!\n", name));
183 return NT_STATUS_OBJECT_NAME_COLLISION;
186 entry = smb_xmalloc(sizeof(struct vfs_init_function_entry));
187 entry->name = smb_xstrdup(name);
188 entry->vfs_op_tuples = vfs_op_tuples;
190 DLIST_ADD(backends, entry);
191 DEBUG(5, ("Successfully added vfs backend '%s'\n", name));
192 return NT_STATUS_OK;
195 /****************************************************************************
196 initialise default vfs hooks
197 ****************************************************************************/
199 static void vfs_init_default(connection_struct *conn)
201 DEBUG(3, ("Initialising default vfs hooks\n"));
203 memcpy(&conn->vfs.ops, &default_vfs.ops, sizeof(default_vfs.ops));
204 memcpy(&conn->vfs_opaque.ops, &default_vfs.ops, sizeof(default_vfs.ops));
207 /****************************************************************************
208 initialise custom vfs hooks
209 ****************************************************************************/
211 BOOL vfs_init_custom(connection_struct *conn, const char *vfs_object)
213 vfs_op_tuple *ops;
214 char *module_name = NULL;
215 char *module_param = NULL, *p;
216 int i;
217 vfs_handle_struct *handle;
218 struct vfs_init_function_entry *entry;
220 if (!conn||!vfs_object||!vfs_object[0]) {
221 DEBUG(0,("vfs_init_custon() called with NULL pointer or emtpy vfs_object!\n"));
222 return False;
225 if(!backends) static_init_vfs;
227 DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object));
229 module_name = smb_xstrdup(vfs_object);
231 p = strchr(module_name, ':');
233 if (p) {
234 *p = 0;
235 module_param = p+1;
236 trim_char(module_param, ' ', ' ');
239 trim_char(module_name, ' ', ' ');
241 /* First, try to load the module with the new module system */
242 if((entry = vfs_find_backend_entry(module_name)) ||
243 (NT_STATUS_IS_OK(smb_probe_module("vfs", module_name)) &&
244 (entry = vfs_find_backend_entry(module_name)))) {
246 DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
248 if ((ops = entry->vfs_op_tuples) == NULL) {
249 DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object));
250 SAFE_FREE(module_name);
251 return False;
253 } else {
254 DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
255 SAFE_FREE(module_name);
256 return False;
259 handle = (vfs_handle_struct *)talloc_zero(conn->mem_ctx,sizeof(vfs_handle_struct));
260 if (!handle) {
261 DEBUG(0,("talloc_zero() failed!\n"));
262 SAFE_FREE(module_name);
263 return False;
265 memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops));
266 handle->conn = conn;
267 if (module_param) {
268 handle->param = talloc_strdup(conn->mem_ctx, module_param);
270 DLIST_ADD(conn->vfs_handles, handle);
272 for(i=0; ops[i].op != NULL; i++) {
273 DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer));
274 if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) {
275 /* Check whether this operation was already made opaque by different module */
276 if(((void**)&conn->vfs_opaque.ops)[ops[i].type] == ((void**)&default_vfs.ops)[ops[i].type]) {
277 /* No, it isn't overloaded yet. Overload. */
278 DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object));
279 ((void**)&conn->vfs_opaque.ops)[ops[i].type] = ops[i].op;
280 ((vfs_handle_struct **)&conn->vfs_opaque.handles)[ops[i].type] = handle;
283 /* Change current VFS disposition*/
284 DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object));
285 ((void**)&conn->vfs.ops)[ops[i].type] = ops[i].op;
286 ((vfs_handle_struct **)&conn->vfs.handles)[ops[i].type] = handle;
289 SAFE_FREE(module_name);
290 return True;
293 /*****************************************************************
294 Generic VFS init.
295 ******************************************************************/
297 BOOL smbd_vfs_init(connection_struct *conn)
299 const char **vfs_objects;
300 unsigned int i = 0;
301 int j = 0;
303 /* Normal share - initialise with disk access functions */
304 vfs_init_default(conn);
305 vfs_objects = lp_vfs_objects(SNUM(conn));
307 /* Override VFS functions if 'vfs object' was not specified*/
308 if (!vfs_objects || !vfs_objects[0])
309 return True;
311 for (i=0; vfs_objects[i] ;) {
312 i++;
315 for (j=i-1; j >= 0; j--) {
316 if (!vfs_init_custom(conn, vfs_objects[j])) {
317 DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects[j]));
318 return False;
321 return True;
324 /*******************************************************************
325 Check if directory exists.
326 ********************************************************************/
328 BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
330 SMB_STRUCT_STAT st2;
331 BOOL ret;
333 if (!st)
334 st = &st2;
336 if (SMB_VFS_STAT(conn,dname,st) != 0)
337 return(False);
339 ret = S_ISDIR(st->st_mode);
340 if(!ret)
341 errno = ENOTDIR;
343 return ret;
346 /*******************************************************************
347 vfs mkdir wrapper
348 ********************************************************************/
350 int vfs_MkDir(connection_struct *conn, const char *name, mode_t mode)
352 int ret;
353 SMB_STRUCT_STAT sbuf;
355 if(!(ret=SMB_VFS_MKDIR(conn, name, mode))) {
357 inherit_access_acl(conn, name, mode);
360 * Check if high bits should have been set,
361 * then (if bits are missing): add them.
362 * Consider bits automagically set by UNIX, i.e. SGID bit from parent dir.
364 if(mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) &&
365 !SMB_VFS_STAT(conn,name,&sbuf) && (mode & ~sbuf.st_mode))
366 SMB_VFS_CHMOD(conn,name,sbuf.st_mode | (mode & ~sbuf.st_mode));
368 return ret;
371 /*******************************************************************
372 Check if an object exists in the vfs.
373 ********************************************************************/
375 BOOL vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
377 SMB_STRUCT_STAT st;
379 if (!sbuf)
380 sbuf = &st;
382 ZERO_STRUCTP(sbuf);
384 if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
385 return(False);
386 return True;
389 /*******************************************************************
390 Check if a file exists in the vfs.
391 ********************************************************************/
393 BOOL vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
395 SMB_STRUCT_STAT st;
397 if (!sbuf)
398 sbuf = &st;
400 ZERO_STRUCTP(sbuf);
402 if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
403 return False;
404 return(S_ISREG(sbuf->st_mode));
407 /****************************************************************************
408 Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
409 ****************************************************************************/
411 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
413 size_t total=0;
415 while (total < byte_count)
417 ssize_t ret = SMB_VFS_READ(fsp, fsp->fd, buf + total,
418 byte_count - total);
420 if (ret == 0) return total;
421 if (ret == -1) {
422 if (errno == EINTR)
423 continue;
424 else
425 return -1;
427 total += ret;
429 return (ssize_t)total;
432 /****************************************************************************
433 Write data to a fd on the vfs.
434 ****************************************************************************/
436 ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N)
438 size_t total=0;
439 ssize_t ret;
441 while (total < N) {
442 ret = SMB_VFS_WRITE(fsp,fsp->fd,buffer + total,N - total);
444 if (ret == -1)
445 return -1;
446 if (ret == 0)
447 return total;
449 total += ret;
451 return (ssize_t)total;
454 /****************************************************************************
455 An allocate file space call using the vfs interface.
456 Allocates space for a file from a filedescriptor.
457 Returns 0 on success, -1 on failure.
458 ****************************************************************************/
460 int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
462 int ret;
463 SMB_STRUCT_STAT st;
464 connection_struct *conn = fsp->conn;
465 SMB_BIG_UINT space_avail;
466 SMB_BIG_UINT bsize,dfree,dsize;
468 release_level_2_oplocks_on_change(fsp);
471 * Actually try and commit the space on disk....
474 DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
476 if (((SMB_OFF_T)len) < 0) {
477 DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
478 return -1;
481 ret = SMB_VFS_FSTAT(fsp,fsp->fd,&st);
482 if (ret == -1)
483 return ret;
485 if (len == (SMB_BIG_UINT)st.st_size)
486 return 0;
488 if (len < (SMB_BIG_UINT)st.st_size) {
489 /* Shrink - use ftruncate. */
491 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
492 fsp->fsp_name, (double)st.st_size ));
494 flush_write_cache(fsp, SIZECHANGE_FLUSH);
495 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fd, (SMB_OFF_T)len)) != -1) {
496 set_filelen_write_cache(fsp, len);
498 return ret;
501 /* Grow - we need to test if we have enough space. */
503 if (!lp_strict_allocate(SNUM(fsp->conn)))
504 return 0;
506 len -= st.st_size;
507 len /= 1024; /* Len is now number of 1k blocks needed. */
508 space_avail = SMB_VFS_DISK_FREE(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
510 DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
511 fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
513 if (len > space_avail) {
514 errno = ENOSPC;
515 return -1;
518 return 0;
521 /****************************************************************************
522 A vfs set_filelen call.
523 set the length of a file from a filedescriptor.
524 Returns 0 on success, -1 on failure.
525 ****************************************************************************/
527 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
529 int ret;
531 release_level_2_oplocks_on_change(fsp);
532 DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
533 flush_write_cache(fsp, SIZECHANGE_FLUSH);
534 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fd, len)) != -1)
535 set_filelen_write_cache(fsp, len);
537 return ret;
540 /****************************************************************************
541 Transfer some data (n bytes) between two file_struct's.
542 ****************************************************************************/
544 static files_struct *in_fsp;
545 static files_struct *out_fsp;
547 static ssize_t read_fn(int fd, void *buf, size_t len)
549 return SMB_VFS_READ(in_fsp, fd, buf, len);
552 static ssize_t write_fn(int fd, const void *buf, size_t len)
554 return SMB_VFS_WRITE(out_fsp, fd, buf, len);
557 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
559 in_fsp = in;
560 out_fsp = out;
562 return transfer_file_internal(in_fsp->fd, out_fsp->fd, n, read_fn, write_fn);
565 /*******************************************************************
566 A vfs_readdir wrapper which just returns the file name.
567 ********************************************************************/
569 char *vfs_readdirname(connection_struct *conn, void *p)
571 struct dirent *ptr= NULL;
572 char *dname;
574 if (!p)
575 return(NULL);
577 ptr = (struct dirent *)SMB_VFS_READDIR(conn,p);
578 if (!ptr)
579 return(NULL);
581 dname = ptr->d_name;
583 #ifdef NEXT2
584 if (telldir(p) < 0)
585 return(NULL);
586 #endif
588 #ifdef HAVE_BROKEN_READDIR
589 /* using /usr/ucb/cc is BAD */
590 dname = dname - 2;
591 #endif
593 return(dname);
596 /*******************************************************************
597 A wrapper for vfs_chdir().
598 ********************************************************************/
600 int vfs_ChDir(connection_struct *conn, const char *path)
602 int res;
603 static pstring LastDir="";
605 if (strcsequal(path,"."))
606 return(0);
608 if (*path == '/' && strcsequal(LastDir,path))
609 return(0);
611 DEBUG(4,("vfs_ChDir to %s\n",path));
613 res = SMB_VFS_CHDIR(conn,path);
614 if (!res)
615 pstrcpy(LastDir,path);
616 return(res);
619 /* number of list structures for a caching GetWd function. */
620 #define MAX_GETWDCACHE (50)
622 static struct {
623 SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
624 SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
625 char *dos_path; /* The pathname in DOS format. */
626 BOOL valid;
627 } ino_list[MAX_GETWDCACHE];
629 extern BOOL use_getwd_cache;
631 /****************************************************************************
632 Prompte a ptr (to make it recently used)
633 ****************************************************************************/
635 static void array_promote(char *array,int elsize,int element)
637 char *p;
638 if (element == 0)
639 return;
641 p = (char *)malloc(elsize);
643 if (!p) {
644 DEBUG(5,("array_promote: malloc fail\n"));
645 return;
648 memcpy(p,array + element * elsize, elsize);
649 memmove(array + elsize,array,elsize*element);
650 memcpy(array,p,elsize);
651 SAFE_FREE(p);
654 /*******************************************************************
655 Return the absolute current directory path - given a UNIX pathname.
656 Note that this path is returned in DOS format, not UNIX
657 format. Note this can be called with conn == NULL.
658 ********************************************************************/
660 char *vfs_GetWd(connection_struct *conn, char *path)
662 pstring s;
663 static BOOL getwd_cache_init = False;
664 SMB_STRUCT_STAT st, st2;
665 int i;
667 *s = 0;
669 if (!use_getwd_cache)
670 return(SMB_VFS_GETWD(conn,path));
672 /* init the cache */
673 if (!getwd_cache_init) {
674 getwd_cache_init = True;
675 for (i=0;i<MAX_GETWDCACHE;i++) {
676 string_set(&ino_list[i].dos_path,"");
677 ino_list[i].valid = False;
681 /* Get the inode of the current directory, if this doesn't work we're
682 in trouble :-) */
684 if (SMB_VFS_STAT(conn, ".",&st) == -1) {
685 DEBUG(0,("Very strange, couldn't stat \".\" path=%s\n", path));
686 return(SMB_VFS_GETWD(conn,path));
690 for (i=0; i<MAX_GETWDCACHE; i++) {
691 if (ino_list[i].valid) {
693 /* If we have found an entry with a matching inode and dev number
694 then find the inode number for the directory in the cached string.
695 If this agrees with that returned by the stat for the current
696 directory then all is o.k. (but make sure it is a directory all
697 the same...) */
699 if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
700 if (SMB_VFS_STAT(conn,ino_list[i].dos_path,&st2) == 0) {
701 if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
702 (st2.st_mode & S_IFMT) == S_IFDIR) {
703 pstrcpy (path, ino_list[i].dos_path);
705 /* promote it for future use */
706 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
707 return (path);
708 } else {
709 /* If the inode is different then something's changed,
710 scrub the entry and start from scratch. */
711 ino_list[i].valid = False;
718 /* We don't have the information to hand so rely on traditional methods.
719 The very slow getcwd, which spawns a process on some systems, or the
720 not quite so bad getwd. */
722 if (!SMB_VFS_GETWD(conn,s)) {
723 DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",strerror(errno)));
724 return (NULL);
727 pstrcpy(path,s);
729 DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
731 /* add it to the cache */
732 i = MAX_GETWDCACHE - 1;
733 string_set(&ino_list[i].dos_path,s);
734 ino_list[i].dev = st.st_dev;
735 ino_list[i].inode = st.st_ino;
736 ino_list[i].valid = True;
738 /* put it at the top of the list */
739 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
741 return (path);
745 /* check if the file 'nmae' is a symlink, in that case check that it point to
746 a file that reside under the 'dir' tree */
748 static BOOL readlink_check(connection_struct *conn, const char *dir, char *name)
750 BOOL ret = True;
751 pstring flink;
752 pstring cleanlink;
753 pstring savedir;
754 pstring realdir;
755 size_t reallen;
757 if (!vfs_GetWd(conn, savedir)) {
758 DEBUG(0,("couldn't vfs_GetWd for %s %s\n", name, dir));
759 return False;
762 if (vfs_ChDir(conn, dir) != 0) {
763 DEBUG(0,("couldn't vfs_ChDir to %s\n", dir));
764 return False;
767 if (!vfs_GetWd(conn, realdir)) {
768 DEBUG(0,("couldn't vfs_GetWd for %s\n", dir));
769 vfs_ChDir(conn, savedir);
770 return(False);
773 reallen = strlen(realdir);
774 if (realdir[reallen -1] == '/') {
775 reallen--;
776 realdir[reallen] = 0;
779 if (SMB_VFS_READLINK(conn, name, flink, sizeof(pstring) -1) != -1) {
780 DEBUG(3,("reduce_name: file path name %s is a symlink\nChecking it's path\n", name));
781 if (*flink == '/') {
782 pstrcpy(cleanlink, flink);
783 } else {
784 pstrcpy(cleanlink, realdir);
785 pstrcat(cleanlink, "/");
786 pstrcat(cleanlink, flink);
788 unix_clean_name(cleanlink);
790 if (strncmp(cleanlink, realdir, reallen) != 0) {
791 DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n", name, realdir, cleanlink, (int)reallen));
792 ret = False;
796 vfs_ChDir(conn, savedir);
798 return ret;
801 /*******************************************************************
802 Reduce a file name, removing .. elements and checking that
803 it is below dir in the heirachy. This uses vfs_GetWd() and so must be run
804 on the system that has the referenced file system.
805 Widelinks are allowed if widelinks is true.
806 ********************************************************************/
808 BOOL reduce_name(connection_struct *conn, pstring s, const char *dir,BOOL widelinks)
810 #ifndef REDUCE_PATHS
811 return True;
812 #else
813 pstring dir2;
814 pstring wd;
815 pstring base_name;
816 pstring newname;
817 char *p=NULL;
818 BOOL relative = (*s != '/');
820 *dir2 = *wd = *base_name = *newname = 0;
822 if (widelinks) {
823 unix_clean_name(s);
824 /* can't have a leading .. */
825 if (strncmp(s,"..",2) == 0 && (s[2]==0 || s[2]=='/')) {
826 DEBUG(3,("Illegal file name? (%s)\n",s));
827 return(False);
830 if (strlen(s) == 0)
831 pstrcpy(s,"./");
833 return(True);
836 DEBUG(3,("reduce_name [%s] [%s]\n",s,dir));
838 /* remove any double slashes */
839 all_string_sub(s,"//","/",0);
841 pstrcpy(base_name,s);
842 p = strrchr_m(base_name,'/');
844 if (!p)
845 return readlink_check(conn, dir, s);
847 if (!vfs_GetWd(conn,wd)) {
848 DEBUG(0,("couldn't vfs_GetWd for %s %s\n",s,dir));
849 return(False);
852 if (vfs_ChDir(conn,dir) != 0) {
853 DEBUG(0,("couldn't vfs_ChDir to %s\n",dir));
854 return(False);
857 if (!vfs_GetWd(conn,dir2)) {
858 DEBUG(0,("couldn't vfs_GetWd for %s\n",dir));
859 vfs_ChDir(conn,wd);
860 return(False);
863 if (p && (p != base_name)) {
864 *p = 0;
865 if (strcmp(p+1,".")==0)
866 p[1]=0;
867 if (strcmp(p+1,"..")==0)
868 *p = '/';
871 if (vfs_ChDir(conn,base_name) != 0) {
872 vfs_ChDir(conn,wd);
873 DEBUG(3,("couldn't vfs_ChDir for %s %s basename=%s\n",s,dir,base_name));
874 return(False);
877 if (!vfs_GetWd(conn,newname)) {
878 vfs_ChDir(conn,wd);
879 DEBUG(2,("couldn't get vfs_GetWd for %s %s\n",s,base_name));
880 return(False);
883 if (p && (p != base_name)) {
884 pstrcat(newname,"/");
885 pstrcat(newname,p+1);
889 size_t l = strlen(dir2);
890 if (dir2[l-1] == '/')
891 l--;
893 if (strncmp(newname,dir2,l) != 0) {
894 vfs_ChDir(conn,wd);
895 DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n",s,dir2,newname,(int)l));
896 return(False);
899 if (!readlink_check(conn, dir, newname)) {
900 DEBUG(2, ("Bad access attemt? %s is a symlink outside the share path", s));
901 return(False);
904 if (relative) {
905 if (newname[l] == '/')
906 pstrcpy(s,newname + l + 1);
907 else
908 pstrcpy(s,newname+l);
909 } else
910 pstrcpy(s,newname);
913 vfs_ChDir(conn,wd);
915 if (strlen(s) == 0)
916 pstrcpy(s,"./");
918 DEBUG(3,("reduced to %s\n",s));
919 return(True);
920 #endif