00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "includes.h"
00027
00028 #undef DBGC_CLASS
00029 #define DBGC_CLASS DBGC_VFS
00030
00031 static_decl_vfs;
00032
00033 struct vfs_init_function_entry {
00034 char *name;
00035 vfs_op_tuple *vfs_op_tuples;
00036 struct vfs_init_function_entry *prev, *next;
00037 };
00038
00039 static struct vfs_init_function_entry *backends = NULL;
00040
00041
00042
00043
00044
00045 static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name)
00046 {
00047 struct vfs_init_function_entry *entry = backends;
00048
00049 while(entry) {
00050 if (strcmp(entry->name, name)==0) return entry;
00051 entry = entry->next;
00052 }
00053
00054 return NULL;
00055 }
00056
00057 NTSTATUS smb_register_vfs(int version, const char *name, vfs_op_tuple *vfs_op_tuples)
00058 {
00059 struct vfs_init_function_entry *entry = backends;
00060
00061 if ((version != SMB_VFS_INTERFACE_VERSION)) {
00062 DEBUG(0, ("Failed to register vfs module.\n"
00063 "The module was compiled against SMB_VFS_INTERFACE_VERSION %d,\n"
00064 "current SMB_VFS_INTERFACE_VERSION is %d.\n"
00065 "Please recompile against the current Samba Version!\n",
00066 version, SMB_VFS_INTERFACE_VERSION));
00067 return NT_STATUS_OBJECT_TYPE_MISMATCH;
00068 }
00069
00070 if (!name || !name[0] || !vfs_op_tuples) {
00071 DEBUG(0,("smb_register_vfs() called with NULL pointer or empty name!\n"));
00072 return NT_STATUS_INVALID_PARAMETER;
00073 }
00074
00075 if (vfs_find_backend_entry(name)) {
00076 DEBUG(0,("VFS module %s already loaded!\n", name));
00077 return NT_STATUS_OBJECT_NAME_COLLISION;
00078 }
00079
00080 entry = SMB_XMALLOC_P(struct vfs_init_function_entry);
00081 entry->name = smb_xstrdup(name);
00082 entry->vfs_op_tuples = vfs_op_tuples;
00083
00084 DLIST_ADD(backends, entry);
00085 DEBUG(5, ("Successfully added vfs backend '%s'\n", name));
00086 return NT_STATUS_OK;
00087 }
00088
00089
00090
00091
00092
00093 static void vfs_init_default(connection_struct *conn)
00094 {
00095 DEBUG(3, ("Initialising default vfs hooks\n"));
00096 vfs_init_custom(conn, DEFAULT_VFS_MODULE_NAME);
00097 }
00098
00099
00100
00101
00102
00103 static inline void vfs_set_operation(struct vfs_ops * vfs, vfs_op_type which,
00104 struct vfs_handle_struct * handle, void * op)
00105 {
00106 ((struct vfs_handle_struct **)&vfs->handles)[which] = handle;
00107 ((void **)(void *)&vfs->ops)[which] = op;
00108 }
00109
00110 BOOL vfs_init_custom(connection_struct *conn, const char *vfs_object)
00111 {
00112 vfs_op_tuple *ops;
00113 char *module_name = NULL;
00114 char *module_param = NULL, *p;
00115 int i;
00116 vfs_handle_struct *handle;
00117 struct vfs_init_function_entry *entry;
00118
00119 if (!conn||!vfs_object||!vfs_object[0]) {
00120 DEBUG(0,("vfs_init_custon() called with NULL pointer or emtpy vfs_object!\n"));
00121 return False;
00122 }
00123
00124 if(!backends) {
00125 static_init_vfs;
00126 }
00127
00128 DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object));
00129
00130 module_name = smb_xstrdup(vfs_object);
00131
00132 p = strchr_m(module_name, ':');
00133
00134 if (p) {
00135 *p = 0;
00136 module_param = p+1;
00137 trim_char(module_param, ' ', ' ');
00138 }
00139
00140 trim_char(module_name, ' ', ' ');
00141
00142
00143 if((entry = vfs_find_backend_entry(module_name)) ||
00144 (NT_STATUS_IS_OK(smb_probe_module("vfs", module_name)) &&
00145 (entry = vfs_find_backend_entry(module_name)))) {
00146
00147 DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
00148
00149 if ((ops = entry->vfs_op_tuples) == NULL) {
00150 DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object));
00151 SAFE_FREE(module_name);
00152 return False;
00153 }
00154 } else {
00155 DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
00156 SAFE_FREE(module_name);
00157 return False;
00158 }
00159
00160 handle = TALLOC_ZERO_P(conn->mem_ctx,vfs_handle_struct);
00161 if (!handle) {
00162 DEBUG(0,("TALLOC_ZERO() failed!\n"));
00163 SAFE_FREE(module_name);
00164 return False;
00165 }
00166 memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops));
00167 handle->conn = conn;
00168 if (module_param) {
00169 handle->param = talloc_strdup(conn->mem_ctx, module_param);
00170 }
00171 DLIST_ADD(conn->vfs_handles, handle);
00172
00173 for(i=0; ops[i].op != NULL; i++) {
00174 DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer));
00175 if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) {
00176
00177
00178
00179 DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object));
00180 vfs_set_operation(&conn->vfs_opaque, ops[i].type, handle, ops[i].op);
00181 }
00182
00183 DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object));
00184 vfs_set_operation(&conn->vfs, ops[i].type, handle, ops[i].op);
00185 }
00186
00187 SAFE_FREE(module_name);
00188 return True;
00189 }
00190
00191
00192
00193
00194
00195
00196
00197 #define EXT_DATA_AREA(e) ((uint8 *)(e) + sizeof(struct vfs_fsp_data))
00198
00199 void *vfs_add_fsp_extension_notype(vfs_handle_struct *handle, files_struct *fsp, size_t ext_size)
00200 {
00201 struct vfs_fsp_data *ext;
00202 void * ext_data;
00203
00204
00205 if ((ext_data = vfs_fetch_fsp_extension(handle, fsp))) {
00206 return ext_data;
00207 }
00208
00209 ext = (struct vfs_fsp_data *)TALLOC_ZERO(
00210 handle->conn->mem_ctx, sizeof(struct vfs_fsp_data) + ext_size);
00211 if (ext == NULL) {
00212 return NULL;
00213 }
00214
00215 ext->owner = handle;
00216 ext->next = fsp->vfs_extension;
00217 fsp->vfs_extension = ext;
00218 return EXT_DATA_AREA(ext);
00219 }
00220
00221 void vfs_remove_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
00222 {
00223 struct vfs_fsp_data *curr;
00224 struct vfs_fsp_data *prev;
00225
00226 for (curr = fsp->vfs_extension, prev = NULL;
00227 curr;
00228 prev = curr, curr = curr->next) {
00229 if (curr->owner == handle) {
00230 if (prev) {
00231 prev->next = curr->next;
00232 } else {
00233 fsp->vfs_extension = curr->next;
00234 }
00235 TALLOC_FREE(curr);
00236 return;
00237 }
00238 }
00239 }
00240
00241 void *vfs_fetch_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
00242 {
00243 struct vfs_fsp_data *head;
00244
00245 for (head = fsp->vfs_extension; head; head = head->next) {
00246 if (head->owner == handle) {
00247 return EXT_DATA_AREA(head);
00248 }
00249 }
00250
00251 return NULL;
00252 }
00253
00254 #undef EXT_DATA_AREA
00255
00256
00257
00258
00259
00260 BOOL smbd_vfs_init(connection_struct *conn)
00261 {
00262 const char **vfs_objects;
00263 unsigned int i = 0;
00264 int j = 0;
00265
00266
00267 vfs_init_default(conn);
00268 vfs_objects = lp_vfs_objects(SNUM(conn));
00269
00270
00271 if (!vfs_objects || !vfs_objects[0])
00272 return True;
00273
00274 for (i=0; vfs_objects[i] ;) {
00275 i++;
00276 }
00277
00278 for (j=i-1; j >= 0; j--) {
00279 if (!vfs_init_custom(conn, vfs_objects[j])) {
00280 DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects[j]));
00281 return False;
00282 }
00283 }
00284 return True;
00285 }
00286
00287
00288
00289
00290
00291 BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
00292 {
00293 SMB_STRUCT_STAT st2;
00294 BOOL ret;
00295
00296 if (!st)
00297 st = &st2;
00298
00299 if (SMB_VFS_STAT(conn,dname,st) != 0)
00300 return(False);
00301
00302 ret = S_ISDIR(st->st_mode);
00303 if(!ret)
00304 errno = ENOTDIR;
00305
00306 return ret;
00307 }
00308
00309
00310
00311
00312
00313 BOOL vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
00314 {
00315 SMB_STRUCT_STAT st;
00316
00317 if (!sbuf)
00318 sbuf = &st;
00319
00320 ZERO_STRUCTP(sbuf);
00321
00322 if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
00323 return(False);
00324 return True;
00325 }
00326
00327
00328
00329
00330
00331 BOOL vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
00332 {
00333 SMB_STRUCT_STAT st;
00334
00335 if (!sbuf)
00336 sbuf = &st;
00337
00338 ZERO_STRUCTP(sbuf);
00339
00340 if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
00341 return False;
00342 return(S_ISREG(sbuf->st_mode));
00343 }
00344
00345
00346
00347
00348
00349 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
00350 {
00351 size_t total=0;
00352
00353 while (total < byte_count)
00354 {
00355 ssize_t ret = SMB_VFS_READ(fsp, fsp->fh->fd, buf + total,
00356 byte_count - total);
00357
00358 if (ret == 0) return total;
00359 if (ret == -1) {
00360 if (errno == EINTR)
00361 continue;
00362 else
00363 return -1;
00364 }
00365 total += ret;
00366 }
00367 return (ssize_t)total;
00368 }
00369
00370 ssize_t vfs_pread_data(files_struct *fsp, char *buf,
00371 size_t byte_count, SMB_OFF_T offset)
00372 {
00373 size_t total=0;
00374
00375 while (total < byte_count)
00376 {
00377 ssize_t ret = SMB_VFS_PREAD(fsp, fsp->fh->fd, buf + total,
00378 byte_count - total, offset + total);
00379
00380 if (ret == 0) return total;
00381 if (ret == -1) {
00382 if (errno == EINTR)
00383 continue;
00384 else
00385 return -1;
00386 }
00387 total += ret;
00388 }
00389 return (ssize_t)total;
00390 }
00391
00392
00393
00394
00395
00396 ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N)
00397 {
00398 size_t total=0;
00399 ssize_t ret;
00400
00401 while (total < N) {
00402 ret = SMB_VFS_WRITE(fsp,fsp->fh->fd,buffer + total,N - total);
00403
00404 if (ret == -1)
00405 return -1;
00406 if (ret == 0)
00407 return total;
00408
00409 total += ret;
00410 }
00411 return (ssize_t)total;
00412 }
00413
00414 ssize_t vfs_pwrite_data(files_struct *fsp,const char *buffer,
00415 size_t N, SMB_OFF_T offset)
00416 {
00417 size_t total=0;
00418 ssize_t ret;
00419
00420 while (total < N) {
00421 ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, buffer + total,
00422 N - total, offset + total);
00423
00424 if (ret == -1)
00425 return -1;
00426 if (ret == 0)
00427 return total;
00428
00429 total += ret;
00430 }
00431 return (ssize_t)total;
00432 }
00433
00434
00435
00436
00437
00438
00439 int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
00440 {
00441 int ret;
00442 SMB_STRUCT_STAT st;
00443 connection_struct *conn = fsp->conn;
00444 SMB_BIG_UINT space_avail;
00445 SMB_BIG_UINT bsize,dfree,dsize;
00446
00447 release_level_2_oplocks_on_change(fsp);
00448
00449
00450
00451
00452
00453 DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
00454
00455 if (((SMB_OFF_T)len) < 0) {
00456 DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
00457 errno = EINVAL;
00458 return -1;
00459 }
00460
00461 ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
00462 if (ret == -1)
00463 return ret;
00464
00465 if (len == (SMB_BIG_UINT)st.st_size)
00466 return 0;
00467
00468 if (len < (SMB_BIG_UINT)st.st_size) {
00469
00470
00471 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
00472 fsp->fsp_name, (double)st.st_size ));
00473
00474 flush_write_cache(fsp, SIZECHANGE_FLUSH);
00475 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, (SMB_OFF_T)len)) != -1) {
00476 set_filelen_write_cache(fsp, len);
00477 }
00478 return ret;
00479 }
00480
00481
00482
00483 if (!lp_strict_allocate(SNUM(fsp->conn)))
00484 return 0;
00485
00486 len -= st.st_size;
00487 len /= 1024;
00488 space_avail = get_dfree_info(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
00489 if (space_avail == (SMB_BIG_UINT)-1) {
00490 return -1;
00491 }
00492
00493 DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
00494 fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
00495
00496 if (len > space_avail) {
00497 errno = ENOSPC;
00498 return -1;
00499 }
00500
00501 return 0;
00502 }
00503
00504
00505
00506
00507
00508
00509
00510 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
00511 {
00512 int ret;
00513
00514 release_level_2_oplocks_on_change(fsp);
00515 DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
00516 flush_write_cache(fsp, SIZECHANGE_FLUSH);
00517 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, len)) != -1) {
00518 set_filelen_write_cache(fsp, len);
00519 notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
00520 FILE_NOTIFY_CHANGE_SIZE
00521 | FILE_NOTIFY_CHANGE_ATTRIBUTES,
00522 fsp->fsp_name);
00523 }
00524
00525 return ret;
00526 }
00527
00528
00529
00530
00531
00532
00533
00534
00535 static char *sparse_buf;
00536 #define SPARSE_BUF_WRITE_SIZE (32*1024)
00537
00538 int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
00539 {
00540 int ret;
00541 SMB_STRUCT_STAT st;
00542 SMB_OFF_T offset;
00543 size_t total;
00544 size_t num_to_write;
00545 ssize_t pwrite_ret;
00546
00547 release_level_2_oplocks_on_change(fsp);
00548 ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
00549 if (ret == -1) {
00550 return ret;
00551 }
00552
00553 if (len <= st.st_size) {
00554 return 0;
00555 }
00556
00557 DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to len %.0f (%.0f bytes)\n",
00558 fsp->fsp_name, (double)st.st_size, (double)len, (double)(len - st.st_size)));
00559
00560 flush_write_cache(fsp, SIZECHANGE_FLUSH);
00561
00562 if (!sparse_buf) {
00563 sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE);
00564 if (!sparse_buf) {
00565 errno = ENOMEM;
00566 return -1;
00567 }
00568 }
00569
00570 offset = st.st_size;
00571 num_to_write = len - st.st_size;
00572 total = 0;
00573
00574 while (total < num_to_write) {
00575 size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (num_to_write - total));
00576
00577 pwrite_ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, sparse_buf, curr_write_size, offset + total);
00578 if (pwrite_ret == -1) {
00579 DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s\n",
00580 fsp->fsp_name, strerror(errno) ));
00581 return -1;
00582 }
00583 if (pwrite_ret == 0) {
00584 return 0;
00585 }
00586
00587 total += pwrite_ret;
00588 }
00589
00590 set_filelen_write_cache(fsp, len);
00591 return 0;
00592 }
00593
00594
00595
00596
00597
00598 static files_struct *in_fsp;
00599 static files_struct *out_fsp;
00600
00601 static ssize_t read_fn(int fd, void *buf, size_t len)
00602 {
00603 return SMB_VFS_READ(in_fsp, fd, buf, len);
00604 }
00605
00606 static ssize_t write_fn(int fd, const void *buf, size_t len)
00607 {
00608 return SMB_VFS_WRITE(out_fsp, fd, buf, len);
00609 }
00610
00611 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
00612 {
00613 in_fsp = in;
00614 out_fsp = out;
00615
00616 return transfer_file_internal(in_fsp->fh->fd, out_fsp->fh->fd, n, read_fn, write_fn);
00617 }
00618
00619
00620
00621
00622
00623 char *vfs_readdirname(connection_struct *conn, void *p)
00624 {
00625 SMB_STRUCT_DIRENT *ptr= NULL;
00626 char *dname;
00627
00628 if (!p)
00629 return(NULL);
00630
00631 ptr = SMB_VFS_READDIR(conn, (DIR *)p);
00632 if (!ptr)
00633 return(NULL);
00634
00635 dname = ptr->d_name;
00636
00637 #ifdef NEXT2
00638 if (telldir(p) < 0)
00639 return(NULL);
00640 #endif
00641
00642 #ifdef HAVE_BROKEN_READDIR_NAME
00643
00644 dname = dname - 2;
00645 #endif
00646
00647 return(dname);
00648 }
00649
00650
00651
00652
00653
00654 int vfs_ChDir(connection_struct *conn, const char *path)
00655 {
00656 int res;
00657 static pstring LastDir="";
00658
00659 if (strcsequal(path,"."))
00660 return(0);
00661
00662 if (*path == '/' && strcsequal(LastDir,path))
00663 return(0);
00664
00665 DEBUG(4,("vfs_ChDir to %s\n",path));
00666
00667 res = SMB_VFS_CHDIR(conn,path);
00668 if (!res)
00669 pstrcpy(LastDir,path);
00670 return(res);
00671 }
00672
00673
00674 #define MAX_GETWDCACHE (50)
00675
00676 static struct {
00677 SMB_DEV_T dev;
00678 SMB_INO_T inode;
00679 char *dos_path;
00680 BOOL valid;
00681 } ino_list[MAX_GETWDCACHE];
00682
00683 extern BOOL use_getwd_cache;
00684
00685
00686
00687
00688
00689 static void array_promote(char *array,int elsize,int element)
00690 {
00691 char *p;
00692 if (element == 0)
00693 return;
00694
00695 p = (char *)SMB_MALLOC(elsize);
00696
00697 if (!p) {
00698 DEBUG(5,("array_promote: malloc fail\n"));
00699 return;
00700 }
00701
00702 memcpy(p,array + element * elsize, elsize);
00703 memmove(array + elsize,array,elsize*element);
00704 memcpy(array,p,elsize);
00705 SAFE_FREE(p);
00706 }
00707
00708
00709
00710
00711
00712
00713
00714 char *vfs_GetWd(connection_struct *conn, char *path)
00715 {
00716 pstring s;
00717 static BOOL getwd_cache_init = False;
00718 SMB_STRUCT_STAT st, st2;
00719 int i;
00720
00721 *s = 0;
00722
00723 if (!use_getwd_cache)
00724 return(SMB_VFS_GETWD(conn,path));
00725
00726
00727 if (!getwd_cache_init) {
00728 getwd_cache_init = True;
00729 for (i=0;i<MAX_GETWDCACHE;i++) {
00730 string_set(&ino_list[i].dos_path,"");
00731 ino_list[i].valid = False;
00732 }
00733 }
00734
00735
00736
00737
00738 if (SMB_VFS_STAT(conn, ".",&st) == -1) {
00739
00740
00741 DEBUG(1,("vfs_GetWd: couldn't stat \".\" path=%s error %s (NFS problem ?)\n", path, strerror(errno) ));
00742 return(SMB_VFS_GETWD(conn,path));
00743 }
00744
00745
00746 for (i=0; i<MAX_GETWDCACHE; i++) {
00747 if (ino_list[i].valid) {
00748
00749
00750
00751
00752
00753
00754
00755 if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
00756 if (SMB_VFS_STAT(conn,ino_list[i].dos_path,&st2) == 0) {
00757 if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
00758 (st2.st_mode & S_IFMT) == S_IFDIR) {
00759 pstrcpy (path, ino_list[i].dos_path);
00760
00761
00762 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
00763 return (path);
00764 } else {
00765
00766
00767 ino_list[i].valid = False;
00768 }
00769 }
00770 }
00771 }
00772 }
00773
00774
00775
00776
00777
00778 if (!SMB_VFS_GETWD(conn,s)) {
00779 DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",strerror(errno)));
00780 return (NULL);
00781 }
00782
00783 pstrcpy(path,s);
00784
00785 DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
00786
00787
00788 i = MAX_GETWDCACHE - 1;
00789 string_set(&ino_list[i].dos_path,s);
00790 ino_list[i].dev = st.st_dev;
00791 ino_list[i].inode = st.st_ino;
00792 ino_list[i].valid = True;
00793
00794
00795 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
00796
00797 return (path);
00798 }
00799
00800
00801
00802
00803
00804
00805 NTSTATUS reduce_name(connection_struct *conn, const pstring fname)
00806 {
00807 #ifdef REALPATH_TAKES_NULL
00808 BOOL free_resolved_name = True;
00809 #else
00810 #ifdef PATH_MAX
00811 char resolved_name_buf[PATH_MAX+1];
00812 #else
00813 pstring resolved_name_buf;
00814 #endif
00815 BOOL free_resolved_name = False;
00816 #endif
00817 char *resolved_name = NULL;
00818 size_t con_path_len = strlen(conn->connectpath);
00819 char *p = NULL;
00820
00821 DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
00822
00823 #ifdef REALPATH_TAKES_NULL
00824 resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
00825 #else
00826 resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
00827 #endif
00828
00829 if (!resolved_name) {
00830 switch (errno) {
00831 case ENOTDIR:
00832 DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
00833 return map_nt_error_from_unix(errno);
00834 case ENOENT:
00835 {
00836 pstring tmp_fname;
00837 fstring last_component;
00838
00839
00840 pstrcpy(tmp_fname, fname);
00841 p = strrchr_m(tmp_fname, '/');
00842 if (p) {
00843 *p++ = '\0';
00844 fstrcpy(last_component, p);
00845 } else {
00846 fstrcpy(last_component, tmp_fname);
00847 pstrcpy(tmp_fname, ".");
00848 }
00849
00850 #ifdef REALPATH_TAKES_NULL
00851 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
00852 #else
00853 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
00854 #endif
00855 if (!resolved_name) {
00856 DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
00857 return map_nt_error_from_unix(errno);
00858 }
00859 pstrcpy(tmp_fname, resolved_name);
00860 pstrcat(tmp_fname, "/");
00861 pstrcat(tmp_fname, last_component);
00862 #ifdef REALPATH_TAKES_NULL
00863 SAFE_FREE(resolved_name);
00864 resolved_name = SMB_STRDUP(tmp_fname);
00865 if (!resolved_name) {
00866 DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
00867 return NT_STATUS_NO_MEMORY;
00868 }
00869 #else
00870 #ifdef PATH_MAX
00871 safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
00872 #else
00873 pstrcpy(resolved_name_buf, tmp_fname);
00874 #endif
00875 resolved_name = resolved_name_buf;
00876 #endif
00877 break;
00878 }
00879 default:
00880 DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
00881 return map_nt_error_from_unix(errno);
00882 }
00883 }
00884
00885 DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
00886
00887 if (*resolved_name != '/') {
00888 DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
00889 if (free_resolved_name) {
00890 SAFE_FREE(resolved_name);
00891 }
00892 return NT_STATUS_OBJECT_NAME_INVALID;
00893 }
00894
00895
00896 if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) {
00897 DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
00898 if (free_resolved_name) {
00899 SAFE_FREE(resolved_name);
00900 }
00901 return NT_STATUS_ACCESS_DENIED;
00902 }
00903
00904
00905
00906
00907
00908 #ifdef S_ISLNK
00909 if (!lp_symlinks(SNUM(conn))) {
00910 SMB_STRUCT_STAT statbuf;
00911 if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
00912 (S_ISLNK(statbuf.st_mode)) ) {
00913 if (free_resolved_name) {
00914 SAFE_FREE(resolved_name);
00915 }
00916 DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
00917 return NT_STATUS_ACCESS_DENIED;
00918 }
00919 }
00920 #endif
00921
00922 DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name));
00923 if (free_resolved_name) {
00924 SAFE_FREE(resolved_name);
00925 }
00926 return NT_STATUS_OK;
00927 }