A small patch from metze to fix builds on some platforms ...
[Samba.git] / source3 / smbd / vfs.c
blobde682793d53890e0a40d7e628f75fb7d79f939cb
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 = {
51 .ops = {
52 /* Disk operations */
54 vfswrap_dummy_connect,
55 vfswrap_dummy_disconnect,
56 vfswrap_disk_free,
57 vfswrap_get_quota,
58 vfswrap_set_quota,
60 /* Directory operations */
62 vfswrap_opendir,
63 vfswrap_readdir,
64 vfswrap_mkdir,
65 vfswrap_rmdir,
66 vfswrap_closedir,
68 /* File operations */
70 vfswrap_open,
71 vfswrap_close,
72 vfswrap_read,
73 vfswrap_write,
74 vfswrap_lseek,
75 vfswrap_sendfile,
76 vfswrap_rename,
77 vfswrap_fsync,
78 vfswrap_stat,
79 vfswrap_fstat,
80 vfswrap_lstat,
81 vfswrap_unlink,
82 vfswrap_chmod,
83 vfswrap_fchmod,
84 vfswrap_chown,
85 vfswrap_fchown,
86 vfswrap_chdir,
87 vfswrap_getwd,
88 vfswrap_utime,
89 vfswrap_ftruncate,
90 vfswrap_lock,
91 vfswrap_symlink,
92 vfswrap_readlink,
93 vfswrap_link,
94 vfswrap_mknod,
95 vfswrap_realpath,
97 vfswrap_fget_nt_acl,
98 vfswrap_get_nt_acl,
99 vfswrap_fset_nt_acl,
100 vfswrap_set_nt_acl,
102 /* POSIX ACL operations. */
103 #if defined(HAVE_NO_ACLS)
104 NULL,
105 NULL,
106 #else
107 vfswrap_chmod_acl,
108 vfswrap_fchmod_acl,
109 #endif
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
135 /****************************************************************************
136 maintain the list of available backends
137 ****************************************************************************/
139 static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name)
141 struct vfs_init_function_entry *entry = backends;
142 pstring stripped;
144 module_path_get_name(name, stripped);
146 while(entry) {
147 if (strequal(entry->name, stripped)) return entry;
148 entry = entry->next;
151 return NULL;
154 NTSTATUS smb_register_vfs(int version, const char *name, vfs_op_tuple *vfs_op_tuples)
156 struct vfs_init_function_entry *entry = backends;
158 if ((version != SMB_VFS_INTERFACE_VERSION)) {
159 DEBUG(0, ("Failed to register vfs module.\n"
160 "The module was compiled against SMB_VFS_INTERFACE_VERSION %d,\n"
161 "current SMB_VFS_INTERFACE_VERSION is %d.\n"
162 "Please recompile against the current Samba Version!\n",
163 version, SMB_VFS_INTERFACE_VERSION));
164 return NT_STATUS_OBJECT_TYPE_MISMATCH;
167 if (!name || !name[0] || !vfs_op_tuples) {
168 DEBUG(0,("smb_register_vfs() called with NULL pointer or empty name!\n"));
169 return NT_STATUS_INVALID_PARAMETER;
172 if (vfs_find_backend_entry(name)) {
173 DEBUG(0,("VFS module %s already loaded!\n", name));
174 return NT_STATUS_OBJECT_NAME_COLLISION;
177 entry = smb_xmalloc(sizeof(struct vfs_init_function_entry));
178 entry->name = smb_xstrdup(name);
179 entry->vfs_op_tuples = vfs_op_tuples;
181 DLIST_ADD(backends, entry);
182 DEBUG(5, ("Successfully added vfs backend '%s'\n", name));
183 return NT_STATUS_OK;
186 /****************************************************************************
187 initialise default vfs hooks
188 ****************************************************************************/
190 static void vfs_init_default(connection_struct *conn)
192 DEBUG(3, ("Initialising default vfs hooks\n"));
194 memcpy(&conn->vfs.ops, &default_vfs.ops, sizeof(default_vfs.ops));
195 memcpy(&conn->vfs_opaque.ops, &default_vfs.ops, sizeof(default_vfs.ops));
198 /****************************************************************************
199 initialise custom vfs hooks
200 ****************************************************************************/
202 BOOL vfs_init_custom(connection_struct *conn, const char *vfs_object)
204 vfs_op_tuple *ops;
205 char *module_name = NULL;
206 char *module_param = NULL, *p;
207 int i;
208 vfs_handle_struct *handle;
209 struct vfs_init_function_entry *entry;
211 if (!conn||!vfs_object||!vfs_object[0]) {
212 DEBUG(0,("vfs_init_custon() called with NULL pointer or emtpy vfs_object!\n"));
213 return False;
216 if(!backends) static_init_vfs;
218 DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object));
220 module_name = smb_xstrdup(vfs_object);
222 p = strchr(module_name, ':');
224 if (p) {
225 *p = 0;
226 module_param = p+1;
227 trim_string(module_param, " ", " ");
230 trim_string(module_name, " ", " ");
232 /* First, try to load the module with the new module system */
233 if((entry = vfs_find_backend_entry(module_name)) ||
234 (NT_STATUS_IS_OK(smb_probe_module("vfs", module_name)) &&
235 (entry = vfs_find_backend_entry(module_name)))) {
237 DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
239 if ((ops = entry->vfs_op_tuples) == NULL) {
240 DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object));
241 SAFE_FREE(module_name);
242 return False;
244 } else {
245 DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
246 SAFE_FREE(module_name);
247 return False;
250 handle = (vfs_handle_struct *)talloc_zero(conn->mem_ctx,sizeof(vfs_handle_struct));
251 if (!handle) {
252 DEBUG(0,("talloc_zero() failed!\n"));
253 SAFE_FREE(module_name);
254 return False;
256 memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops));
257 handle->conn = conn;
258 if (module_param) {
259 handle->param = talloc_strdup(conn->mem_ctx, module_param);
261 DLIST_ADD(conn->vfs_handles, handle);
263 for(i=0; ops[i].op != NULL; i++) {
264 DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer));
265 if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) {
266 /* Check whether this operation was already made opaque by different module */
267 if(((void**)&conn->vfs_opaque.ops)[ops[i].type] == ((void**)&default_vfs.ops)[ops[i].type]) {
268 /* No, it isn't overloaded yet. Overload. */
269 DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object));
270 ((void**)&conn->vfs_opaque.ops)[ops[i].type] = ops[i].op;
271 ((vfs_handle_struct **)&conn->vfs_opaque.handles)[ops[i].type] = handle;
274 /* Change current VFS disposition*/
275 DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object));
276 ((void**)&conn->vfs.ops)[ops[i].type] = ops[i].op;
277 ((vfs_handle_struct **)&conn->vfs.handles)[ops[i].type] = handle;
280 SAFE_FREE(module_name);
281 return True;
284 /*****************************************************************
285 Generic VFS init.
286 ******************************************************************/
288 BOOL smbd_vfs_init(connection_struct *conn)
290 const char **vfs_objects;
291 unsigned int i = 0;
292 int j = 0;
294 /* Normal share - initialise with disk access functions */
295 vfs_init_default(conn);
296 vfs_objects = lp_vfs_objects(SNUM(conn));
298 /* Override VFS functions if 'vfs object' was not specified*/
299 if (!vfs_objects || !vfs_objects[0])
300 return True;
302 for (i=0; vfs_objects[i] ;) {
303 i++;
306 for (j=i-1; j >= 0; j--) {
307 if (!vfs_init_custom(conn, vfs_objects[j])) {
308 DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects[j]));
309 return False;
312 return True;
315 /*******************************************************************
316 Check if directory exists.
317 ********************************************************************/
319 BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
321 SMB_STRUCT_STAT st2;
322 BOOL ret;
324 if (!st)
325 st = &st2;
327 if (VFS_STAT(conn,dname,st) != 0)
328 return(False);
330 ret = S_ISDIR(st->st_mode);
331 if(!ret)
332 errno = ENOTDIR;
334 return ret;
337 /*******************************************************************
338 vfs mkdir wrapper
339 ********************************************************************/
341 int vfs_MkDir(connection_struct *conn, const char *name, mode_t mode)
343 int ret;
344 SMB_STRUCT_STAT sbuf;
346 if(!(ret=VFS_MKDIR(conn, name, mode))) {
348 inherit_access_acl(conn, name, mode);
351 * Check if high bits should have been set,
352 * then (if bits are missing): add them.
353 * Consider bits automagically set by UNIX, i.e. SGID bit from parent dir.
355 if(mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) &&
356 !VFS_STAT(conn,name,&sbuf) && (mode & ~sbuf.st_mode))
357 VFS_CHMOD(conn,name,sbuf.st_mode | (mode & ~sbuf.st_mode));
359 return ret;
362 /*******************************************************************
363 Check if an object exists in the vfs.
364 ********************************************************************/
366 BOOL vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
368 SMB_STRUCT_STAT st;
370 if (!sbuf)
371 sbuf = &st;
373 ZERO_STRUCTP(sbuf);
375 if (VFS_STAT(conn,fname,sbuf) == -1)
376 return(False);
377 return True;
380 /*******************************************************************
381 Check if a file exists in the vfs.
382 ********************************************************************/
384 BOOL vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
386 SMB_STRUCT_STAT st;
388 if (!sbuf)
389 sbuf = &st;
391 ZERO_STRUCTP(sbuf);
393 if (VFS_STAT(conn,fname,sbuf) == -1)
394 return False;
395 return(S_ISREG(sbuf->st_mode));
398 /****************************************************************************
399 Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
400 ****************************************************************************/
402 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
404 size_t total=0;
406 while (total < byte_count)
408 ssize_t ret = VFS_READ(fsp, fsp->fd, buf + total,
409 byte_count - total);
411 if (ret == 0) return total;
412 if (ret == -1) {
413 if (errno == EINTR)
414 continue;
415 else
416 return -1;
418 total += ret;
420 return (ssize_t)total;
423 /****************************************************************************
424 Write data to a fd on the vfs.
425 ****************************************************************************/
427 ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N)
429 size_t total=0;
430 ssize_t ret;
432 while (total < N) {
433 ret = VFS_WRITE(fsp,fsp->fd,buffer + total,N - total);
435 if (ret == -1)
436 return -1;
437 if (ret == 0)
438 return total;
440 total += ret;
442 return (ssize_t)total;
445 /****************************************************************************
446 An allocate file space call using the vfs interface.
447 Allocates space for a file from a filedescriptor.
448 Returns 0 on success, -1 on failure.
449 ****************************************************************************/
451 int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
453 int ret;
454 SMB_STRUCT_STAT st;
455 connection_struct *conn = fsp->conn;
456 SMB_BIG_UINT space_avail;
457 SMB_BIG_UINT bsize,dfree,dsize;
459 release_level_2_oplocks_on_change(fsp);
462 * Actually try and commit the space on disk....
465 DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
467 if (((SMB_OFF_T)len) < 0) {
468 DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
469 return -1;
472 ret = VFS_FSTAT(fsp,fsp->fd,&st);
473 if (ret == -1)
474 return ret;
476 if (len == (SMB_BIG_UINT)st.st_size)
477 return 0;
479 if (len < (SMB_BIG_UINT)st.st_size) {
480 /* Shrink - use ftruncate. */
482 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
483 fsp->fsp_name, (double)st.st_size ));
485 flush_write_cache(fsp, SIZECHANGE_FLUSH);
486 if ((ret = VFS_FTRUNCATE(fsp, fsp->fd, (SMB_OFF_T)len)) != -1) {
487 set_filelen_write_cache(fsp, len);
489 return ret;
492 /* Grow - we need to test if we have enough space. */
494 if (!lp_strict_allocate(SNUM(fsp->conn)))
495 return 0;
497 len -= st.st_size;
498 len /= 1024; /* Len is now number of 1k blocks needed. */
499 space_avail = VFS_DISK_FREE(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
501 DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
502 fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
504 if (len > space_avail) {
505 errno = ENOSPC;
506 return -1;
509 return 0;
512 /****************************************************************************
513 A vfs set_filelen call.
514 set the length of a file from a filedescriptor.
515 Returns 0 on success, -1 on failure.
516 ****************************************************************************/
518 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
520 int ret;
522 release_level_2_oplocks_on_change(fsp);
523 DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
524 flush_write_cache(fsp, SIZECHANGE_FLUSH);
525 if ((ret = VFS_FTRUNCATE(fsp, fsp->fd, len)) != -1)
526 set_filelen_write_cache(fsp, len);
528 return ret;
531 /****************************************************************************
532 Transfer some data (n bytes) between two file_struct's.
533 ****************************************************************************/
535 static files_struct *in_fsp;
536 static files_struct *out_fsp;
538 static ssize_t read_fn(int fd, void *buf, size_t len)
540 return VFS_READ(in_fsp, fd, buf, len);
543 static ssize_t write_fn(int fd, const void *buf, size_t len)
545 return VFS_WRITE(out_fsp, fd, buf, len);
548 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
550 in_fsp = in;
551 out_fsp = out;
553 return transfer_file_internal(in_fsp->fd, out_fsp->fd, n, read_fn, write_fn);
556 /*******************************************************************
557 A vfs_readdir wrapper which just returns the file name.
558 ********************************************************************/
560 char *vfs_readdirname(connection_struct *conn, void *p)
562 struct dirent *ptr= NULL;
563 char *dname;
565 if (!p)
566 return(NULL);
568 ptr = (struct dirent *)VFS_READDIR(conn,p);
569 if (!ptr)
570 return(NULL);
572 dname = ptr->d_name;
574 #ifdef NEXT2
575 if (telldir(p) < 0)
576 return(NULL);
577 #endif
579 #ifdef HAVE_BROKEN_READDIR
580 /* using /usr/ucb/cc is BAD */
581 dname = dname - 2;
582 #endif
584 return(dname);
587 /*******************************************************************
588 A wrapper for vfs_chdir().
589 ********************************************************************/
591 int vfs_ChDir(connection_struct *conn, const char *path)
593 int res;
594 static pstring LastDir="";
596 if (strcsequal(path,"."))
597 return(0);
599 if (*path == '/' && strcsequal(LastDir,path))
600 return(0);
602 DEBUG(4,("vfs_ChDir to %s\n",path));
604 res = VFS_CHDIR(conn,path);
605 if (!res)
606 pstrcpy(LastDir,path);
607 return(res);
610 /* number of list structures for a caching GetWd function. */
611 #define MAX_GETWDCACHE (50)
613 static struct {
614 SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
615 SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
616 char *dos_path; /* The pathname in DOS format. */
617 BOOL valid;
618 } ino_list[MAX_GETWDCACHE];
620 extern BOOL use_getwd_cache;
622 /****************************************************************************
623 Prompte a ptr (to make it recently used)
624 ****************************************************************************/
626 static void array_promote(char *array,int elsize,int element)
628 char *p;
629 if (element == 0)
630 return;
632 p = (char *)malloc(elsize);
634 if (!p) {
635 DEBUG(5,("array_promote: malloc fail\n"));
636 return;
639 memcpy(p,array + element * elsize, elsize);
640 memmove(array + elsize,array,elsize*element);
641 memcpy(array,p,elsize);
642 SAFE_FREE(p);
645 /*******************************************************************
646 Return the absolute current directory path - given a UNIX pathname.
647 Note that this path is returned in DOS format, not UNIX
648 format. Note this can be called with conn == NULL.
649 ********************************************************************/
651 char *vfs_GetWd(connection_struct *conn, char *path)
653 pstring s;
654 static BOOL getwd_cache_init = False;
655 SMB_STRUCT_STAT st, st2;
656 int i;
658 *s = 0;
660 if (!use_getwd_cache)
661 return(VFS_GETWD(conn,path));
663 /* init the cache */
664 if (!getwd_cache_init) {
665 getwd_cache_init = True;
666 for (i=0;i<MAX_GETWDCACHE;i++) {
667 string_set(&ino_list[i].dos_path,"");
668 ino_list[i].valid = False;
672 /* Get the inode of the current directory, if this doesn't work we're
673 in trouble :-) */
675 if (VFS_STAT(conn, ".",&st) == -1) {
676 DEBUG(0,("Very strange, couldn't stat \".\" path=%s\n", path));
677 return(VFS_GETWD(conn,path));
681 for (i=0; i<MAX_GETWDCACHE; i++) {
682 if (ino_list[i].valid) {
684 /* If we have found an entry with a matching inode and dev number
685 then find the inode number for the directory in the cached string.
686 If this agrees with that returned by the stat for the current
687 directory then all is o.k. (but make sure it is a directory all
688 the same...) */
690 if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
691 if (VFS_STAT(conn,ino_list[i].dos_path,&st2) == 0) {
692 if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
693 (st2.st_mode & S_IFMT) == S_IFDIR) {
694 pstrcpy (path, ino_list[i].dos_path);
696 /* promote it for future use */
697 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
698 return (path);
699 } else {
700 /* If the inode is different then something's changed,
701 scrub the entry and start from scratch. */
702 ino_list[i].valid = False;
709 /* We don't have the information to hand so rely on traditional methods.
710 The very slow getcwd, which spawns a process on some systems, or the
711 not quite so bad getwd. */
713 if (!VFS_GETWD(conn,s)) {
714 DEBUG(0,("vfs_GetWd: VFS_GETWD call failed, errno %s\n",strerror(errno)));
715 return (NULL);
718 pstrcpy(path,s);
720 DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
722 /* add it to the cache */
723 i = MAX_GETWDCACHE - 1;
724 string_set(&ino_list[i].dos_path,s);
725 ino_list[i].dev = st.st_dev;
726 ino_list[i].inode = st.st_ino;
727 ino_list[i].valid = True;
729 /* put it at the top of the list */
730 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
732 return (path);
736 /* check if the file 'nmae' is a symlink, in that case check that it point to
737 a file that reside under the 'dir' tree */
739 static BOOL readlink_check(connection_struct *conn, const char *dir, char *name)
741 BOOL ret = True;
742 pstring flink;
743 pstring cleanlink;
744 pstring savedir;
745 pstring realdir;
746 size_t reallen;
748 if (!vfs_GetWd(conn, savedir)) {
749 DEBUG(0,("couldn't vfs_GetWd for %s %s\n", name, dir));
750 return False;
753 if (vfs_ChDir(conn, dir) != 0) {
754 DEBUG(0,("couldn't vfs_ChDir to %s\n", dir));
755 return False;
758 if (!vfs_GetWd(conn, realdir)) {
759 DEBUG(0,("couldn't vfs_GetWd for %s\n", dir));
760 vfs_ChDir(conn, savedir);
761 return(False);
764 reallen = strlen(realdir);
765 if (realdir[reallen -1] == '/') {
766 reallen--;
767 realdir[reallen] = 0;
770 if (VFS_READLINK(conn, name, flink, sizeof(pstring) -1) != -1) {
771 DEBUG(3,("reduce_name: file path name %s is a symlink\nChecking it's path\n", name));
772 if (*flink == '/') {
773 pstrcpy(cleanlink, flink);
774 } else {
775 pstrcpy(cleanlink, realdir);
776 pstrcat(cleanlink, "/");
777 pstrcat(cleanlink, flink);
779 unix_clean_name(cleanlink);
781 if (strncmp(cleanlink, realdir, reallen) != 0) {
782 DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n", name, realdir, cleanlink, (int)reallen));
783 ret = False;
787 vfs_ChDir(conn, savedir);
789 return ret;
792 /*******************************************************************
793 Reduce a file name, removing .. elements and checking that
794 it is below dir in the heirachy. This uses vfs_GetWd() and so must be run
795 on the system that has the referenced file system.
796 Widelinks are allowed if widelinks is true.
797 ********************************************************************/
799 BOOL reduce_name(connection_struct *conn, pstring s, const char *dir,BOOL widelinks)
801 #ifndef REDUCE_PATHS
802 return True;
803 #else
804 pstring dir2;
805 pstring wd;
806 pstring base_name;
807 pstring newname;
808 char *p=NULL;
809 BOOL relative = (*s != '/');
811 *dir2 = *wd = *base_name = *newname = 0;
813 if (widelinks) {
814 unix_clean_name(s);
815 /* can't have a leading .. */
816 if (strncmp(s,"..",2) == 0 && (s[2]==0 || s[2]=='/')) {
817 DEBUG(3,("Illegal file name? (%s)\n",s));
818 return(False);
821 if (strlen(s) == 0)
822 pstrcpy(s,"./");
824 return(True);
827 DEBUG(3,("reduce_name [%s] [%s]\n",s,dir));
829 /* remove any double slashes */
830 all_string_sub(s,"//","/",0);
832 pstrcpy(base_name,s);
833 p = strrchr_m(base_name,'/');
835 if (!p)
836 return readlink_check(conn, dir, s);
838 if (!vfs_GetWd(conn,wd)) {
839 DEBUG(0,("couldn't vfs_GetWd for %s %s\n",s,dir));
840 return(False);
843 if (vfs_ChDir(conn,dir) != 0) {
844 DEBUG(0,("couldn't vfs_ChDir to %s\n",dir));
845 return(False);
848 if (!vfs_GetWd(conn,dir2)) {
849 DEBUG(0,("couldn't vfs_GetWd for %s\n",dir));
850 vfs_ChDir(conn,wd);
851 return(False);
854 if (p && (p != base_name)) {
855 *p = 0;
856 if (strcmp(p+1,".")==0)
857 p[1]=0;
858 if (strcmp(p+1,"..")==0)
859 *p = '/';
862 if (vfs_ChDir(conn,base_name) != 0) {
863 vfs_ChDir(conn,wd);
864 DEBUG(3,("couldn't vfs_ChDir for %s %s basename=%s\n",s,dir,base_name));
865 return(False);
868 if (!vfs_GetWd(conn,newname)) {
869 vfs_ChDir(conn,wd);
870 DEBUG(2,("couldn't get vfs_GetWd for %s %s\n",s,base_name));
871 return(False);
874 if (p && (p != base_name)) {
875 pstrcat(newname,"/");
876 pstrcat(newname,p+1);
880 size_t l = strlen(dir2);
881 if (dir2[l-1] == '/')
882 l--;
884 if (strncmp(newname,dir2,l) != 0) {
885 vfs_ChDir(conn,wd);
886 DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n",s,dir2,newname,(int)l));
887 return(False);
890 if (!readlink_check(conn, dir, newname)) {
891 DEBUG(2, ("Bad access attemt? %s is a symlink outside the share path", s));
892 return(False);
895 if (relative) {
896 if (newname[l] == '/')
897 pstrcpy(s,newname + l + 1);
898 else
899 pstrcpy(s,newname+l);
900 } else
901 pstrcpy(s,newname);
904 vfs_ChDir(conn,wd);
906 if (strlen(s) == 0)
907 pstrcpy(s,"./");
909 DEBUG(3,("reduced to %s\n",s));
910 return(True);
911 #endif