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 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. 12 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. 17 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. 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 30struct vfs_init_function_entry { 31 char *name; 32 vfs_op_tuple *vfs_op_tuples; 33 struct vfs_init_function_entry *prev, *next; 34}; 35 36static struct vfs_init_function_entry *backends = NULL; 37 38/* Some structures to help us initialise the vfs operations table */ 39 40struct vfs_syminfo { 41 char *name; 42 void *fptr; 43}; 44 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. */ 48 49static struct vfs_ops default_vfs = { 50 51 { 52 /* Disk operations */ 53 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, 60 61 /* Directory operations */ 62 63 vfswrap_opendir, 64 vfswrap_readdir, 65 vfswrap_seekdir, 66 vfswrap_telldir, 67 vfswrap_rewinddir, 68 vfswrap_mkdir, 69 vfswrap_rmdir, 70 vfswrap_closedir, 71 72 /* File operations */ 73 74 vfswrap_open, 75 vfswrap_close, 76 vfswrap_read, 77 vfswrap_pread, 78 vfswrap_write, 79 vfswrap_pwrite, 80 vfswrap_lseek, 81 vfswrap_sendfile, 82 vfswrap_rename, 83 vfswrap_fsync, 84 vfswrap_stat, 85 vfswrap_fstat, 86 vfswrap_lstat, 87 vfswrap_unlink, 88 vfswrap_chmod, 89 vfswrap_fchmod, 90 vfswrap_chown, 91 vfswrap_fchown, 92 vfswrap_chdir, 93 vfswrap_getwd, 94 vfswrap_utime, 95 vfswrap_ftruncate, 96 vfswrap_lock, 97 vfswrap_symlink, 98 vfswrap_readlink, 99 vfswrap_link, 100 vfswrap_mknod, 101 vfswrap_realpath, 102 103 /* Windows ACL operations. */ 104 vfswrap_fget_nt_acl, 105 vfswrap_get_nt_acl, 106 vfswrap_fset_nt_acl, 107 vfswrap_set_nt_acl, 108 109 /* POSIX ACL operations. */ 110 vfswrap_chmod_acl, 111 vfswrap_fchmod_acl, 112 113 vfswrap_sys_acl_get_entry, 114 vfswrap_sys_acl_get_tag_type, 115 vfswrap_sys_acl_get_permset, 116 vfswrap_sys_acl_get_qualifier, 117 vfswrap_sys_acl_get_file, 118 vfswrap_sys_acl_get_fd, 119 vfswrap_sys_acl_clear_perms, 120 vfswrap_sys_acl_add_perm, 121 vfswrap_sys_acl_to_text, 122 vfswrap_sys_acl_init, 123 vfswrap_sys_acl_create_entry, 124 vfswrap_sys_acl_set_tag_type, 125 vfswrap_sys_acl_set_qualifier, 126 vfswrap_sys_acl_set_permset, 127 vfswrap_sys_acl_valid, 128 vfswrap_sys_acl_set_file, 129 vfswrap_sys_acl_set_fd, 130 vfswrap_sys_acl_delete_def_file, 131 vfswrap_sys_acl_get_perm, 132 vfswrap_sys_acl_free_text, 133 vfswrap_sys_acl_free_acl, 134 vfswrap_sys_acl_free_qualifier, 135 136 /* EA operations. */ 137 vfswrap_getxattr, 138 vfswrap_lgetxattr, 139 vfswrap_fgetxattr, 140 vfswrap_listxattr, 141 vfswrap_llistxattr, 142 vfswrap_flistxattr, 143 vfswrap_removexattr, 144 vfswrap_lremovexattr, 145 vfswrap_fremovexattr, 146 vfswrap_setxattr, 147 vfswrap_lsetxattr, 148 vfswrap_fsetxattr 149 } 150}; 151 152/**************************************************************************** 153 maintain the list of available backends 154****************************************************************************/ 155 156static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name) 157{ 158 struct vfs_init_function_entry *entry = backends; 159 160 while(entry) { 161 if (strcmp(entry->name, name)==0) return entry; 162 entry = entry->next; 163 } 164 165 return NULL; 166} 167 168NTSTATUS smb_register_vfs(int version, const char *name, vfs_op_tuple *vfs_op_tuples) 169{ 170 struct vfs_init_function_entry *entry = backends; 171 172 if ((version != SMB_VFS_INTERFACE_VERSION)) { 173 DEBUG(0, ("Failed to register vfs module.\n" 174 "The module was compiled against SMB_VFS_INTERFACE_VERSION %d,\n" 175 "current SMB_VFS_INTERFACE_VERSION is %d.\n" 176 "Please recompile against the current Samba Version!\n", 177 version, SMB_VFS_INTERFACE_VERSION)); 178 return NT_STATUS_OBJECT_TYPE_MISMATCH; 179 } 180 181 if (!name || !name[0] || !vfs_op_tuples) { 182 DEBUG(0,("smb_register_vfs() called with NULL pointer or empty name!\n")); 183 return NT_STATUS_INVALID_PARAMETER; 184 } 185 186 if (vfs_find_backend_entry(name)) { 187 DEBUG(0,("VFS module %s already loaded!\n", name)); 188 return NT_STATUS_OBJECT_NAME_COLLISION; 189 } 190 191 entry = SMB_XMALLOC_P(struct vfs_init_function_entry); 192 entry->name = smb_xstrdup(name); 193 entry->vfs_op_tuples = vfs_op_tuples; 194 195 DLIST_ADD(backends, entry); 196 DEBUG(5, ("Successfully added vfs backend '%s'\n", name)); 197 return NT_STATUS_OK; 198} 199 200/**************************************************************************** 201 initialise default vfs hooks 202****************************************************************************/ 203 204static void vfs_init_default(connection_struct *conn) 205{ 206 DEBUG(3, ("Initialising default vfs hooks\n")); 207 208 memcpy(&conn->vfs.ops, &default_vfs.ops, sizeof(default_vfs.ops)); 209 memcpy(&conn->vfs_opaque.ops, &default_vfs.ops, sizeof(default_vfs.ops)); 210} 211 212/**************************************************************************** 213 initialise custom vfs hooks 214 ****************************************************************************/ 215 216BOOL vfs_init_custom(connection_struct *conn, const char *vfs_object) 217{ 218 vfs_op_tuple *ops; 219 char *module_name = NULL; 220 char *module_param = NULL, *p; 221 int i; 222 vfs_handle_struct *handle; 223 struct vfs_init_function_entry *entry; 224 225 if (!conn||!vfs_object||!vfs_object[0]) { 226 DEBUG(0,("vfs_init_custon() called with NULL pointer or emtpy vfs_object!\n")); 227 return False; 228 } 229 230 if(!backends) static_init_vfs; 231 232 DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object)); 233 234 module_name = smb_xstrdup(vfs_object); 235 236 p = strchr(module_name, ':'); 237 238 if (p) { 239 *p = 0; 240 module_param = p+1; 241 trim_char(module_param, ' ', ' '); 242 } 243 244 trim_char(module_name, ' ', ' '); 245 246 /* First, try to load the module with the new module system */ 247 if((entry = vfs_find_backend_entry(module_name)) || 248 (NT_STATUS_IS_OK(smb_probe_module("vfs", module_name)) && 249 (entry = vfs_find_backend_entry(module_name)))) { 250 251 DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object)); 252 253 if ((ops = entry->vfs_op_tuples) == NULL) { 254 DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object)); 255 SAFE_FREE(module_name); 256 return False; 257 } 258 } else { 259 DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object)); 260 SAFE_FREE(module_name); 261 return False; 262 } 263 264 handle = TALLOC_ZERO_P(conn->mem_ctx,vfs_handle_struct); 265 if (!handle) { 266 DEBUG(0,("talloc_zero() failed!\n")); 267 SAFE_FREE(module_name); 268 return False; 269 } 270 memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops)); 271 handle->conn = conn; 272 if (module_param) { 273 handle->param = talloc_strdup(conn->mem_ctx, module_param); 274 } 275 DLIST_ADD(conn->vfs_handles, handle); 276 277 for(i=0; ops[i].op != NULL; i++) { 278 DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer)); 279 if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) { 280 /* Check whether this operation was already made opaque by different module */ 281 if(((void**)&conn->vfs_opaque.ops)[ops[i].type] == ((void**)&default_vfs.ops)[ops[i].type]) { 282 /* No, it isn't overloaded yet. Overload. */ 283 DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object)); 284 ((void**)&conn->vfs_opaque.ops)[ops[i].type] = ops[i].op; 285 ((vfs_handle_struct **)&conn->vfs_opaque.handles)[ops[i].type] = handle; 286 } 287 } 288 /* Change current VFS disposition*/ 289 DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object)); 290 ((void**)&conn->vfs.ops)[ops[i].type] = ops[i].op; 291 ((vfs_handle_struct **)&conn->vfs.handles)[ops[i].type] = handle; 292 } 293 294 SAFE_FREE(module_name); 295 return True; 296} 297 298/***************************************************************** 299 Generic VFS init. 300******************************************************************/ 301 302BOOL smbd_vfs_init(connection_struct *conn) 303{ 304 const char **vfs_objects; 305 unsigned int i = 0; 306 int j = 0; 307 308 /* Normal share - initialise with disk access functions */ 309 vfs_init_default(conn); 310 vfs_objects = lp_vfs_objects(SNUM(conn)); 311 312 /* Override VFS functions if 'vfs object' was not specified*/ 313 if (!vfs_objects || !vfs_objects[0]) 314 return True; 315 316 for (i=0; vfs_objects[i] ;) { 317 i++; 318 } 319 320 for (j=i-1; j >= 0; j--) { 321 if (!vfs_init_custom(conn, vfs_objects[j])) { 322 DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects[j])); 323 return False; 324 } 325 } 326 return True; 327} 328 329/******************************************************************* 330 Check if directory exists. 331********************************************************************/ 332 333BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st) 334{ 335 SMB_STRUCT_STAT st2; 336 BOOL ret; 337 338 if (!st) 339 st = &st2; 340 341 if (SMB_VFS_STAT(conn,dname,st) != 0) 342 return(False); 343 344 ret = S_ISDIR(st->st_mode); 345 if(!ret) 346 errno = ENOTDIR; 347 348 return ret; 349} 350 351/******************************************************************* 352 vfs mkdir wrapper 353********************************************************************/ 354 355int vfs_MkDir(connection_struct *conn, const char *name, mode_t mode) 356{ 357 int ret; 358 SMB_STRUCT_STAT sbuf; 359 360 if(!(ret=SMB_VFS_MKDIR(conn, name, mode))) { 361 362 inherit_access_acl(conn, name, mode); 363 364 /* 365 * Check if high bits should have been set, 366 * then (if bits are missing): add them. 367 * Consider bits automagically set by UNIX, i.e. SGID bit from parent dir. 368 */ 369 if(mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) && 370 !SMB_VFS_STAT(conn,name,&sbuf) && (mode & ~sbuf.st_mode)) 371 SMB_VFS_CHMOD(conn,name,sbuf.st_mode | (mode & ~sbuf.st_mode)); 372 } 373 return ret; 374} 375 376/******************************************************************* 377 Check if an object exists in the vfs. 378********************************************************************/ 379 380BOOL vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf) 381{ 382 SMB_STRUCT_STAT st; 383 384 if (!sbuf) 385 sbuf = &st; 386 387 ZERO_STRUCTP(sbuf); 388 389 if (SMB_VFS_STAT(conn,fname,sbuf) == -1) 390 return(False); 391 return True; 392} 393 394/******************************************************************* 395 Check if a file exists in the vfs. 396********************************************************************/ 397 398BOOL vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf) 399{ 400 SMB_STRUCT_STAT st; 401 402 if (!sbuf) 403 sbuf = &st; 404 405 ZERO_STRUCTP(sbuf); 406 407 if (SMB_VFS_STAT(conn,fname,sbuf) == -1) 408 return False; 409 return(S_ISREG(sbuf->st_mode)); 410} 411 412/**************************************************************************** 413 Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data) 414****************************************************************************/ 415 416ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count) 417{ 418 size_t total=0; 419 420 while (total < byte_count) 421 { 422 ssize_t ret = SMB_VFS_READ(fsp, fsp->fd, buf + total, 423 byte_count - total); 424 425 if (ret == 0) return total; 426 if (ret == -1) { 427 if (errno == EINTR) 428 continue; 429 else 430 return -1; 431 } 432 total += ret; 433 } 434 return (ssize_t)total; 435} 436 437ssize_t vfs_pread_data(files_struct *fsp, char *buf, 438 size_t byte_count, SMB_OFF_T offset) 439{ 440 size_t total=0; 441 442 while (total < byte_count) 443 { 444 ssize_t ret = SMB_VFS_PREAD(fsp, fsp->fd, buf + total, 445 byte_count - total, offset + total); 446 447 if (ret == 0) return total; 448 if (ret == -1) { 449 if (errno == EINTR) 450 continue; 451 else 452 return -1; 453 } 454 total += ret; 455 } 456 return (ssize_t)total; 457} 458 459/**************************************************************************** 460 Write data to a fd on the vfs. 461****************************************************************************/ 462 463ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N) 464{ 465 size_t total=0; 466 ssize_t ret; 467 468 while (total < N) { 469 ret = SMB_VFS_WRITE(fsp,fsp->fd,buffer + total,N - total); 470 471 if (ret == -1) 472 return -1; 473 if (ret == 0) 474 return total; 475 476 total += ret; 477 } 478 return (ssize_t)total; 479} 480 481/* Foxconn modified start pling 11/18/2009 */ 482//ssize_t vfs_pwrite_data(files_struct *fsp,const char *buffer, 483// size_t N, SMB_OFF_T offset) 484ssize_t vfs_pwrite_data(files_struct *fsp,const char *buffer, 485 size_t N, SMB_BIG_UINT offset) 486/* Foxconn modified end pling 11/18/2009 */ 487{ 488 /* Foxconn modified start pling 11/18/2009 */ 489 //size_t total=0; 490 //ssize_t ret; 491 SMB_BIG_UINT total=0; 492 SMB_BIG_UINT ret; 493 /* Foxconn modified end pling 11/18/2009 */ 494 495 while (total < N) { 496 ret = SMB_VFS_PWRITE(fsp, fsp->fd, buffer + total, 497 N - total, offset + total); 498 499 if (ret == -1) 500 return -1; 501 if (ret == 0) 502 return total; 503 504 total += ret; 505 } 506 return (ssize_t)total; 507} 508/**************************************************************************** 509 An allocate file space call using the vfs interface. 510 Allocates space for a file from a filedescriptor. 511 Returns 0 on success, -1 on failure. 512****************************************************************************/ 513 514int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len) 515{ 516 int ret; 517 SMB_STRUCT_STAT st; 518 connection_struct *conn = fsp->conn; 519 SMB_BIG_UINT space_avail; 520 SMB_BIG_UINT bsize,dfree,dsize; 521 522 release_level_2_oplocks_on_change(fsp); 523 524 /* 525 * Actually try and commit the space on disk.... 526 */ 527 528 DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len )); 529 530 /* Foxconn removed start pling 11/18/2009 */ 531 /* Don't check negative length, to avoid "disk full" error 532 * when copy file from Vista/Win7 to USB. 533 */ 534#if 0 535 if (((SMB_OFF_T)len) < 0) { 536 DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name )); 537 return -1; 538 } 539#endif 540 /* Foxconn removed end pling 11/18/2009 */ 541 542 ret = SMB_VFS_FSTAT(fsp,fsp->fd,&st); 543 if (ret == -1) 544 return ret; 545 546 if (len == (SMB_BIG_UINT)st.st_size) 547 return 0; 548 549 if (len < (SMB_BIG_UINT)st.st_size) { 550 /* Shrink - use ftruncate. */ 551 552 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n", 553 fsp->fsp_name, (double)st.st_size )); 554 555 flush_write_cache(fsp, SIZECHANGE_FLUSH); 556 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fd, (SMB_OFF_T)len)) != -1) { 557 set_filelen_write_cache(fsp, len); 558 } 559 return ret; 560 } 561 562 /* Grow - we need to test if we have enough space. */ 563 564 if (!lp_strict_allocate(SNUM(fsp->conn))) 565 return 0; 566 567 len -= st.st_size; 568 len /= 1024; /* Len is now number of 1k blocks needed. */ 569 space_avail = SMB_VFS_DISK_FREE(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize); 570 if (space_avail == (SMB_BIG_UINT)-1) { 571 return -1; 572 } 573 574 DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n", 575 fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail )); 576 577 if (len > space_avail) { 578 errno = ENOSPC; 579 return -1; 580 } 581 582 return 0; 583} 584 585/**************************************************************************** 586 A vfs set_filelen call. 587 set the length of a file from a filedescriptor. 588 Returns 0 on success, -1 on failure. 589****************************************************************************/ 590 591int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len) 592{ 593 int ret; 594 595 release_level_2_oplocks_on_change(fsp); 596 DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len)); 597 flush_write_cache(fsp, SIZECHANGE_FLUSH); 598 599 /* foxconn modified start, zacker, 07/07/2011 */ 600 /* Workaround: ftruncate is slow in VFAT, just do it 601 * for small (16MB) file editing, to workaround the 602 * edit problem with notepad in Windows 603 * */ 604 if (len > 0 && len < 0x1000000) { 605 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fd, len)) != -1) 606 set_filelen_write_cache(fsp, len); 607 } else { 608 ret = 0; 609 } 610 /* foxconn modified end, zacker, 07/07/2011 */ 611 612 ret = 0; 613 /* foxconn modified end , 04/01/2009 */ 614 615 return ret; 616} 617 618/**************************************************************************** 619 Transfer some data (n bytes) between two file_struct's. 620****************************************************************************/ 621 622static files_struct *in_fsp; 623static files_struct *out_fsp; 624 625static ssize_t read_fn(int fd, void *buf, size_t len) 626{ 627 return SMB_VFS_READ(in_fsp, fd, buf, len); 628} 629 630static ssize_t write_fn(int fd, const void *buf, size_t len) 631{ 632 return SMB_VFS_WRITE(out_fsp, fd, buf, len); 633} 634 635SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n) 636{ 637 in_fsp = in; 638 out_fsp = out; 639 640 return transfer_file_internal(in_fsp->fd, out_fsp->fd, n, read_fn, write_fn); 641} 642 643/******************************************************************* 644 A vfs_readdir wrapper which just returns the file name. 645********************************************************************/ 646 647char *vfs_readdirname(connection_struct *conn, void *p) 648{ 649 SMB_STRUCT_DIRENT *ptr= NULL; 650 char *dname; 651 652 if (!p) 653 return(NULL); 654 655 ptr = SMB_VFS_READDIR(conn,p); 656 if (!ptr) 657 return(NULL); 658 659 dname = ptr->d_name; 660 661#ifdef NEXT2 662 if (telldir(p) < 0) 663 return(NULL); 664#endif 665 666#ifdef HAVE_BROKEN_READDIR 667 /* using /usr/ucb/cc is BAD */ 668 dname = dname - 2; 669#endif 670 671 return(dname); 672} 673 674/******************************************************************* 675 A wrapper for vfs_chdir(). 676********************************************************************/ 677 678int vfs_ChDir(connection_struct *conn, const char *path) 679{ 680 int res; 681 static pstring LastDir=""; 682 683 if (strcsequal(path,".")) 684 return(0); 685 686 if (*path == '/' && strcsequal(LastDir,path)) 687 return(0); 688 689 DEBUG(4,("vfs_ChDir to %s\n",path)); 690 691 res = SMB_VFS_CHDIR(conn,path); 692 if (!res) 693 pstrcpy(LastDir,path); 694 return(res); 695} 696 697/* number of list structures for a caching GetWd function. */ 698#define MAX_GETWDCACHE (50) 699 700static struct { 701 SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */ 702 SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */ 703 char *dos_path; /* The pathname in DOS format. */ 704 BOOL valid; 705} ino_list[MAX_GETWDCACHE]; 706 707extern BOOL use_getwd_cache; 708 709/**************************************************************************** 710 Prompte a ptr (to make it recently used) 711****************************************************************************/ 712 713static void array_promote(char *array,int elsize,int element) 714{ 715 char *p; 716 if (element == 0) 717 return; 718 719 p = (char *)SMB_MALLOC(elsize); 720 721 if (!p) { 722 DEBUG(5,("array_promote: malloc fail\n")); 723 return; 724 } 725 726 memcpy(p,array + element * elsize, elsize); 727 memmove(array + elsize,array,elsize*element); 728 memcpy(array,p,elsize); 729 SAFE_FREE(p); 730} 731 732/******************************************************************* 733 Return the absolute current directory path - given a UNIX pathname. 734 Note that this path is returned in DOS format, not UNIX 735 format. Note this can be called with conn == NULL. 736********************************************************************/ 737 738char *vfs_GetWd(connection_struct *conn, char *path) 739{ 740 pstring s; 741 static BOOL getwd_cache_init = False; 742 SMB_STRUCT_STAT st, st2; 743 int i; 744 745 *s = 0; 746 747 if (!use_getwd_cache) 748 return(SMB_VFS_GETWD(conn,path)); 749 750 /* init the cache */ 751 if (!getwd_cache_init) { 752 getwd_cache_init = True; 753 for (i=0;i<MAX_GETWDCACHE;i++) { 754 string_set(&ino_list[i].dos_path,""); 755 ino_list[i].valid = False; 756 } 757 } 758 759 /* Get the inode of the current directory, if this doesn't work we're 760 in trouble :-) */ 761 762 if (SMB_VFS_STAT(conn, ".",&st) == -1) { 763 DEBUG(0,("Very strange, couldn't stat \".\" path=%s\n", path)); 764 return(SMB_VFS_GETWD(conn,path)); 765 } 766 767 768 for (i=0; i<MAX_GETWDCACHE; i++) { 769 if (ino_list[i].valid) { 770 771 /* If we have found an entry with a matching inode and dev number 772 then find the inode number for the directory in the cached string. 773 If this agrees with that returned by the stat for the current 774 directory then all is o.k. (but make sure it is a directory all 775 the same...) */ 776 777 if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) { 778 if (SMB_VFS_STAT(conn,ino_list[i].dos_path,&st2) == 0) { 779 if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev && 780 (st2.st_mode & S_IFMT) == S_IFDIR) { 781 pstrcpy (path, ino_list[i].dos_path); 782 783 /* promote it for future use */ 784 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i); 785 return (path); 786 } else { 787 /* If the inode is different then something's changed, 788 scrub the entry and start from scratch. */ 789 ino_list[i].valid = False; 790 } 791 } 792 } 793 } 794 } 795 796 /* We don't have the information to hand so rely on traditional methods. 797 The very slow getcwd, which spawns a process on some systems, or the 798 not quite so bad getwd. */ 799 800 if (!SMB_VFS_GETWD(conn,s)) { 801 DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",strerror(errno))); 802 return (NULL); 803 } 804 805 pstrcpy(path,s); 806 807 DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev)); 808 809 /* add it to the cache */ 810 i = MAX_GETWDCACHE - 1; 811 string_set(&ino_list[i].dos_path,s); 812 ino_list[i].dev = st.st_dev; 813 ino_list[i].inode = st.st_ino; 814 ino_list[i].valid = True; 815 816 /* put it at the top of the list */ 817 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i); 818 819 return (path); 820} 821 822BOOL canonicalize_path(connection_struct *conn, pstring path) 823{ 824#ifdef REALPATH_TAKES_NULL 825 char *resolved_name = SMB_VFS_REALPATH(conn,path,NULL); 826 if (!resolved_name) { 827 return False; 828 } 829 pstrcpy(path, resolved_name); 830 SAFE_FREE(resolved_name); 831 return True; 832#else 833#ifdef PATH_MAX 834 char resolved_name_buf[PATH_MAX+1]; 835#else 836 pstring resolved_name_buf; 837#endif 838 char *resolved_name = SMB_VFS_REALPATH(conn,path,resolved_name_buf); 839 if (!resolved_name) { 840 return False; 841 } 842 pstrcpy(path, resolved_name); 843 return True; 844#endif /* REALPATH_TAKES_NULL */ 845} 846 847/******************************************************************* 848 Reduce a file name, removing .. elements and checking that 849 it is below dir in the heirachy. This uses realpath. 850********************************************************************/ 851 852BOOL reduce_name(connection_struct *conn, const pstring fname) 853{ 854#ifdef REALPATH_TAKES_NULL 855 BOOL free_resolved_name = True; 856#else 857#ifdef PATH_MAX 858 char resolved_name_buf[PATH_MAX+1]; 859#else 860 pstring resolved_name_buf; 861#endif 862 BOOL free_resolved_name = False; 863#endif 864 char *resolved_name = NULL; 865 size_t con_path_len = strlen(conn->connectpath); 866 char *p = NULL; 867 int saved_errno = errno; 868 869 DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath)); 870 871#ifdef REALPATH_TAKES_NULL 872 resolved_name = SMB_VFS_REALPATH(conn,fname,NULL); 873#else 874 resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf); 875#endif 876 877 if (!resolved_name) { 878 switch (errno) { 879 case ENOTDIR: 880 DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname)); 881 errno = saved_errno; 882 return False; 883 case ENOENT: 884 { 885 pstring tmp_fname; 886 fstring last_component; 887 /* Last component didn't exist. Remove it and try and canonicalise the directory. */ 888 889 pstrcpy(tmp_fname, fname); 890 p = strrchr_m(tmp_fname, '/'); 891 if (p) { 892 *p++ = '\0'; 893 fstrcpy(last_component, p); 894 } else { 895 fstrcpy(last_component, tmp_fname); 896 pstrcpy(tmp_fname, "."); 897 } 898 899#ifdef REALPATH_TAKES_NULL 900 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL); 901#else 902 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf); 903#endif 904 if (!resolved_name) { 905 DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname)); 906 errno = saved_errno; 907 return False; 908 } 909 pstrcpy(tmp_fname, resolved_name); 910 pstrcat(tmp_fname, "/"); 911 pstrcat(tmp_fname, last_component); 912#ifdef REALPATH_TAKES_NULL 913 SAFE_FREE(resolved_name); 914 resolved_name = SMB_STRDUP(tmp_fname); 915 if (!resolved_name) { 916 DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname)); 917 errno = saved_errno; 918 return False; 919 } 920#else 921#ifdef PATH_MAX 922 safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX); 923#else 924 pstrcpy(pstring resolved_name_buf, tmp_fname); 925#endif 926 resolved_name = resolved_name_buf; 927#endif 928 break; 929 } 930 default: 931 DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname)); 932 /* Don't restore the saved errno. We need to return the error that 933 realpath caused here as it was not one of the cases we handle. JRA. */ 934 return False; 935 } 936 } 937 938 DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name)); 939 940 if (*resolved_name != '/') { 941 DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n")); 942 if (free_resolved_name) 943 SAFE_FREE(resolved_name); 944 errno = saved_errno; 945 return False; 946 } 947 948 /* Check for widelinks allowed. */ 949 if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) { 950 DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname)); 951 if (free_resolved_name) 952 SAFE_FREE(resolved_name); 953 errno = EACCES; 954 return False; 955 } 956 957 /* Check if we are allowing users to follow symlinks */ 958 /* Patch from David Clerc <David.Clerc@cui.unige.ch> 959 University of Geneva */ 960 961#ifdef S_ISLNK 962 if (!lp_symlinks(SNUM(conn))) { 963 SMB_STRUCT_STAT statbuf; 964 if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) && 965 (S_ISLNK(statbuf.st_mode)) ) { 966 if (free_resolved_name) 967 SAFE_FREE(resolved_name); 968 DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name)); 969 errno = EACCES; 970 return False; 971 } 972 } 973#endif 974 975 DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name)); 976 if (free_resolved_name) 977 SAFE_FREE(resolved_name); 978 errno = saved_errno; 979 return(True); 980} 981