source: branches/samba-3.0/source/smbd/vfs.c@ 424

Last change on this file since 424 was 424, checked in by Herwig Bauernfeind, 15 years ago

_divers fix for OBJECT_NOT_FOUND error discovered after Ticket #126 fix

File size: 25.8 KB
Line 
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 Copyright (C) James Peach 2006
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22
23 This work was sponsored by Optifacio Software Services, Inc.
24*/
25
26#include "includes.h"
27
28#undef DBGC_CLASS
29#define DBGC_CLASS DBGC_VFS
30
31static_decl_vfs;
32
33struct vfs_init_function_entry {
34 char *name;
35 vfs_op_tuple *vfs_op_tuples;
36 struct vfs_init_function_entry *prev, *next;
37};
38
39static struct vfs_init_function_entry *backends = NULL;
40
41/****************************************************************************
42 maintain the list of available backends
43****************************************************************************/
44
45static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name)
46{
47 struct vfs_init_function_entry *entry = backends;
48
49 while(entry) {
50 if (strcmp(entry->name, name)==0) return entry;
51 entry = entry->next;
52 }
53
54 return NULL;
55}
56
57NTSTATUS smb_register_vfs(int version, const char *name, vfs_op_tuple *vfs_op_tuples)
58{
59 struct vfs_init_function_entry *entry = backends;
60
61 if ((version != SMB_VFS_INTERFACE_VERSION)) {
62 DEBUG(0, ("Failed to register vfs module.\n"
63 "The module was compiled against SMB_VFS_INTERFACE_VERSION %d,\n"
64 "current SMB_VFS_INTERFACE_VERSION is %d.\n"
65 "Please recompile against the current Samba Version!\n",
66 version, SMB_VFS_INTERFACE_VERSION));
67 return NT_STATUS_OBJECT_TYPE_MISMATCH;
68 }
69
70 if (!name || !name[0] || !vfs_op_tuples) {
71 DEBUG(0,("smb_register_vfs() called with NULL pointer or empty name!\n"));
72 return NT_STATUS_INVALID_PARAMETER;
73 }
74
75 if (vfs_find_backend_entry(name)) {
76 DEBUG(0,("VFS module %s already loaded!\n", name));
77 return NT_STATUS_OBJECT_NAME_COLLISION;
78 }
79
80 entry = SMB_XMALLOC_P(struct vfs_init_function_entry);
81 entry->name = smb_xstrdup(name);
82 entry->vfs_op_tuples = vfs_op_tuples;
83
84 DLIST_ADD(backends, entry);
85 DEBUG(5, ("Successfully added vfs backend '%s'\n", name));
86 return NT_STATUS_OK;
87}
88
89/****************************************************************************
90 initialise default vfs hooks
91****************************************************************************/
92
93static void vfs_init_default(connection_struct *conn)
94{
95 DEBUG(3, ("Initialising default vfs hooks\n"));
96 vfs_init_custom(conn, DEFAULT_VFS_MODULE_NAME);
97}
98
99/****************************************************************************
100 initialise custom vfs hooks
101 ****************************************************************************/
102
103static inline void vfs_set_operation(struct vfs_ops * vfs, vfs_op_type which,
104 struct vfs_handle_struct * handle, void * op)
105{
106 ((struct vfs_handle_struct **)&vfs->handles)[which] = handle;
107 ((void **)(void *)&vfs->ops)[which] = op;
108}
109
110BOOL vfs_init_custom(connection_struct *conn, const char *vfs_object)
111{
112 vfs_op_tuple *ops;
113 char *module_name = NULL;
114 char *module_param = NULL, *p;
115 int i;
116 vfs_handle_struct *handle;
117 struct vfs_init_function_entry *entry;
118
119 if (!conn||!vfs_object||!vfs_object[0]) {
120 DEBUG(0,("vfs_init_custon() called with NULL pointer or emtpy vfs_object!\n"));
121 return False;
122 }
123
124 if(!backends) {
125 static_init_vfs;
126 }
127
128 DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object));
129
130 module_name = smb_xstrdup(vfs_object);
131
132 p = strchr_m(module_name, ':');
133
134 if (p) {
135 *p = 0;
136 module_param = p+1;
137 trim_char(module_param, ' ', ' ');
138 }
139
140 trim_char(module_name, ' ', ' ');
141
142 /* First, try to load the module with the new module system */
143 if((entry = vfs_find_backend_entry(module_name)) ||
144 (NT_STATUS_IS_OK(smb_probe_module("vfs", module_name)) &&
145 (entry = vfs_find_backend_entry(module_name)))) {
146
147 DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
148
149 if ((ops = entry->vfs_op_tuples) == NULL) {
150 DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object));
151 SAFE_FREE(module_name);
152 return False;
153 }
154 } else {
155 DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
156 SAFE_FREE(module_name);
157 return False;
158 }
159
160 handle = TALLOC_ZERO_P(conn->mem_ctx,vfs_handle_struct);
161 if (!handle) {
162 DEBUG(0,("TALLOC_ZERO() failed!\n"));
163 SAFE_FREE(module_name);
164 return False;
165 }
166 memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops));
167 handle->conn = conn;
168 if (module_param) {
169 handle->param = talloc_strdup(conn->mem_ctx, module_param);
170 }
171 DLIST_ADD(conn->vfs_handles, handle);
172
173 for(i=0; ops[i].op != NULL; i++) {
174 DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer));
175 if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) {
176 /* If this operation was already made opaque by different module, it
177 * will be overridden here.
178 */
179 DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object));
180 vfs_set_operation(&conn->vfs_opaque, ops[i].type, handle, ops[i].op);
181 }
182 /* Change current VFS disposition*/
183 DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object));
184 vfs_set_operation(&conn->vfs, ops[i].type, handle, ops[i].op);
185 }
186
187 SAFE_FREE(module_name);
188 return True;
189}
190
191/*****************************************************************
192 Allow VFS modules to extend files_struct with VFS-specific state.
193 This will be ok for small numbers of extensions, but might need to
194 be refactored if it becomes more widely used.
195******************************************************************/
196
197#define EXT_DATA_AREA(e) ((uint8 *)(e) + sizeof(struct vfs_fsp_data))
198
199void *vfs_add_fsp_extension_notype(vfs_handle_struct *handle, files_struct *fsp, size_t ext_size)
200{
201 struct vfs_fsp_data *ext;
202 void * ext_data;
203
204 /* Prevent VFS modules adding multiple extensions. */
205 if ((ext_data = vfs_fetch_fsp_extension(handle, fsp))) {
206 return ext_data;
207 }
208
209 ext = (struct vfs_fsp_data *)TALLOC_ZERO(
210 handle->conn->mem_ctx, sizeof(struct vfs_fsp_data) + ext_size);
211 if (ext == NULL) {
212 return NULL;
213 }
214
215 ext->owner = handle;
216 ext->next = fsp->vfs_extension;
217 fsp->vfs_extension = ext;
218 return EXT_DATA_AREA(ext);
219}
220
221void vfs_remove_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
222{
223 struct vfs_fsp_data *curr;
224 struct vfs_fsp_data *prev;
225
226 for (curr = fsp->vfs_extension, prev = NULL;
227 curr;
228 prev = curr, curr = curr->next) {
229 if (curr->owner == handle) {
230 if (prev) {
231 prev->next = curr->next;
232 } else {
233 fsp->vfs_extension = curr->next;
234 }
235 TALLOC_FREE(curr);
236 return;
237 }
238 }
239}
240
241void *vfs_fetch_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
242{
243 struct vfs_fsp_data *head;
244
245 for (head = fsp->vfs_extension; head; head = head->next) {
246 if (head->owner == handle) {
247 return EXT_DATA_AREA(head);
248 }
249 }
250
251 return NULL;
252}
253
254#undef EXT_DATA_AREA
255
256/*****************************************************************
257 Generic VFS init.
258******************************************************************/
259
260BOOL smbd_vfs_init(connection_struct *conn)
261{
262 const char **vfs_objects;
263 unsigned int i = 0;
264 int j = 0;
265
266 /* Normal share - initialise with disk access functions */
267 vfs_init_default(conn);
268 vfs_objects = lp_vfs_objects(SNUM(conn));
269
270 /* Override VFS functions if 'vfs object' was not specified*/
271 if (!vfs_objects || !vfs_objects[0])
272 return True;
273
274 for (i=0; vfs_objects[i] ;) {
275 i++;
276 }
277
278 for (j=i-1; j >= 0; j--) {
279 if (!vfs_init_custom(conn, vfs_objects[j])) {
280 DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects[j]));
281 return False;
282 }
283 }
284 return True;
285}
286
287/*******************************************************************
288 Check if directory exists.
289********************************************************************/
290
291BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
292{
293 SMB_STRUCT_STAT st2;
294 BOOL ret;
295
296 if (!st)
297 st = &st2;
298
299 if (SMB_VFS_STAT(conn,dname,st) != 0)
300 return(False);
301
302 ret = S_ISDIR(st->st_mode);
303 if(!ret)
304 errno = ENOTDIR;
305
306 return ret;
307}
308
309/*******************************************************************
310 Check if an object exists in the vfs.
311********************************************************************/
312
313BOOL vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
314{
315 SMB_STRUCT_STAT st;
316
317 if (!sbuf)
318 sbuf = &st;
319
320 ZERO_STRUCTP(sbuf);
321
322 if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
323 return(False);
324 return True;
325}
326
327/*******************************************************************
328 Check if a file exists in the vfs.
329********************************************************************/
330
331BOOL vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
332{
333 SMB_STRUCT_STAT st;
334
335 if (!sbuf)
336 sbuf = &st;
337
338 ZERO_STRUCTP(sbuf);
339
340 if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
341 return False;
342 return(S_ISREG(sbuf->st_mode));
343}
344
345/****************************************************************************
346 Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
347****************************************************************************/
348
349ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
350{
351 size_t total=0;
352
353 while (total < byte_count)
354 {
355 ssize_t ret = SMB_VFS_READ(fsp, fsp->fh->fd, buf + total,
356 byte_count - total);
357
358 if (ret == 0) return total;
359 if (ret == -1) {
360 if (errno == EINTR)
361 continue;
362 else
363 return -1;
364 }
365 total += ret;
366 }
367 return (ssize_t)total;
368}
369
370ssize_t vfs_pread_data(files_struct *fsp, char *buf,
371 size_t byte_count, SMB_OFF_T offset)
372{
373 size_t total=0;
374
375 while (total < byte_count)
376 {
377 ssize_t ret = SMB_VFS_PREAD(fsp, fsp->fh->fd, buf + total,
378 byte_count - total, offset + total);
379
380 if (ret == 0) return total;
381 if (ret == -1) {
382 if (errno == EINTR)
383 continue;
384 else
385 return -1;
386 }
387 total += ret;
388 }
389 return (ssize_t)total;
390}
391
392/****************************************************************************
393 Write data to a fd on the vfs.
394****************************************************************************/
395
396ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N)
397{
398 size_t total=0;
399 ssize_t ret;
400
401 while (total < N) {
402 ret = SMB_VFS_WRITE(fsp,fsp->fh->fd,buffer + total,N - total);
403
404 if (ret == -1)
405 return -1;
406 if (ret == 0)
407 return total;
408
409 total += ret;
410 }
411 return (ssize_t)total;
412}
413
414ssize_t vfs_pwrite_data(files_struct *fsp,const char *buffer,
415 size_t N, SMB_OFF_T offset)
416{
417 size_t total=0;
418 ssize_t ret;
419
420 while (total < N) {
421 ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, buffer + total,
422 N - total, offset + total);
423
424 if (ret == -1)
425 return -1;
426 if (ret == 0)
427 return total;
428
429 total += ret;
430 }
431 return (ssize_t)total;
432}
433/****************************************************************************
434 An allocate file space call using the vfs interface.
435 Allocates space for a file from a filedescriptor.
436 Returns 0 on success, -1 on failure.
437****************************************************************************/
438
439int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
440{
441 int ret;
442 SMB_STRUCT_STAT st;
443 connection_struct *conn = fsp->conn;
444 SMB_BIG_UINT space_avail;
445 SMB_BIG_UINT bsize,dfree,dsize;
446
447 release_level_2_oplocks_on_change(fsp);
448
449 /*
450 * Actually try and commit the space on disk....
451 */
452
453 DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
454
455 if (((SMB_OFF_T)len) < 0) {
456 DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
457 errno = EINVAL;
458 return -1;
459 }
460
461 ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
462 if (ret == -1)
463 return ret;
464
465 if (len == (SMB_BIG_UINT)st.st_size)
466 return 0;
467
468 if (len < (SMB_BIG_UINT)st.st_size) {
469 /* Shrink - use ftruncate. */
470
471 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
472 fsp->fsp_name, (double)st.st_size ));
473
474 flush_write_cache(fsp, SIZECHANGE_FLUSH);
475 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, (SMB_OFF_T)len)) != -1) {
476 set_filelen_write_cache(fsp, len);
477 }
478 return ret;
479 }
480
481 /* Grow - we need to test if we have enough space. */
482
483 if (!lp_strict_allocate(SNUM(fsp->conn)))
484 return 0;
485
486 len -= st.st_size;
487 len /= 1024; /* Len is now number of 1k blocks needed. */
488 space_avail = get_dfree_info(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
489 if (space_avail == (SMB_BIG_UINT)-1) {
490 return -1;
491 }
492
493 DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
494 fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
495
496 if (len > space_avail) {
497 errno = ENOSPC;
498 return -1;
499 }
500
501 return 0;
502}
503
504/****************************************************************************
505 A vfs set_filelen call.
506 set the length of a file from a filedescriptor.
507 Returns 0 on success, -1 on failure.
508****************************************************************************/
509
510int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
511{
512 int ret;
513
514 release_level_2_oplocks_on_change(fsp);
515 DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
516 flush_write_cache(fsp, SIZECHANGE_FLUSH);
517 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, len)) != -1) {
518 set_filelen_write_cache(fsp, len);
519 notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
520 FILE_NOTIFY_CHANGE_SIZE
521 | FILE_NOTIFY_CHANGE_ATTRIBUTES,
522 fsp->fsp_name);
523 }
524
525 return ret;
526}
527
528/****************************************************************************
529 A vfs fill sparse call.
530 Writes zeros from the end of file to len, if len is greater than EOF.
531 Used only by strict_sync.
532 Returns 0 on success, -1 on failure.
533****************************************************************************/
534
535static char *sparse_buf;
536#define SPARSE_BUF_WRITE_SIZE (32*1024)
537
538int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
539{
540 int ret;
541 SMB_STRUCT_STAT st;
542 SMB_OFF_T offset;
543 size_t total;
544 size_t num_to_write;
545 ssize_t pwrite_ret;
546
547 release_level_2_oplocks_on_change(fsp);
548 ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
549 if (ret == -1) {
550 return ret;
551 }
552
553 if (len <= st.st_size) {
554 return 0;
555 }
556
557 DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to len %.0f (%.0f bytes)\n",
558 fsp->fsp_name, (double)st.st_size, (double)len, (double)(len - st.st_size)));
559
560 flush_write_cache(fsp, SIZECHANGE_FLUSH);
561
562 if (!sparse_buf) {
563 sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE);
564 if (!sparse_buf) {
565 errno = ENOMEM;
566 return -1;
567 }
568 }
569
570 offset = st.st_size;
571 num_to_write = len - st.st_size;
572 total = 0;
573
574 while (total < num_to_write) {
575 size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (num_to_write - total));
576
577 pwrite_ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, sparse_buf, curr_write_size, offset + total);
578 if (pwrite_ret == -1) {
579 DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s\n",
580 fsp->fsp_name, strerror(errno) ));
581 return -1;
582 }
583 if (pwrite_ret == 0) {
584 return 0;
585 }
586
587 total += pwrite_ret;
588 }
589
590 set_filelen_write_cache(fsp, len);
591 return 0;
592}
593
594/****************************************************************************
595 Transfer some data (n bytes) between two file_struct's.
596****************************************************************************/
597
598static files_struct *in_fsp;
599static files_struct *out_fsp;
600
601static ssize_t read_fn(int fd, void *buf, size_t len)
602{
603 return SMB_VFS_READ(in_fsp, fd, buf, len);
604}
605
606static ssize_t write_fn(int fd, const void *buf, size_t len)
607{
608 return SMB_VFS_WRITE(out_fsp, fd, buf, len);
609}
610
611SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
612{
613 in_fsp = in;
614 out_fsp = out;
615
616 return transfer_file_internal(in_fsp->fh->fd, out_fsp->fh->fd, n, read_fn, write_fn);
617}
618
619/*******************************************************************
620 A vfs_readdir wrapper which just returns the file name.
621********************************************************************/
622
623char *vfs_readdirname(connection_struct *conn, void *p)
624{
625 SMB_STRUCT_DIRENT *ptr= NULL;
626 char *dname;
627
628 if (!p)
629 return(NULL);
630
631 ptr = SMB_VFS_READDIR(conn, (DIR *)p);
632 if (!ptr)
633 return(NULL);
634
635 dname = ptr->d_name;
636
637#ifdef NEXT2
638 if (telldir(p) < 0)
639 return(NULL);
640#endif
641
642#ifdef HAVE_BROKEN_READDIR_NAME
643 /* using /usr/ucb/cc is BAD */
644 dname = dname - 2;
645#endif
646
647 return(dname);
648}
649
650/*******************************************************************
651 A wrapper for vfs_chdir().
652********************************************************************/
653
654int vfs_ChDir(connection_struct *conn, const char *path)
655{
656 int res;
657 static pstring LastDir="";
658
659 if (strcsequal(path,"."))
660 return(0);
661
662#ifdef __OS2__
663 if ((*path == '/' || *path == '\\' || (*path && path[1] == ':')) && strcsequal(LastDir,path))
664#else
665 if (*path == '/' && strcsequal(LastDir,path))
666#endif
667 return(0);
668
669 DEBUG(4,("vfs_ChDir to %s\n",path));
670
671 res = SMB_VFS_CHDIR(conn,path);
672 if (!res)
673 pstrcpy(LastDir,path);
674 return(res);
675}
676
677/* number of list structures for a caching GetWd function. */
678#define MAX_GETWDCACHE (50)
679
680static struct {
681 SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
682 SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
683 char *dos_path; /* The pathname in DOS format. */
684 BOOL valid;
685} ino_list[MAX_GETWDCACHE];
686
687extern BOOL use_getwd_cache;
688
689/****************************************************************************
690 Prompte a ptr (to make it recently used)
691****************************************************************************/
692
693static void array_promote(char *array,int elsize,int element)
694{
695 char *p;
696 if (element == 0)
697 return;
698
699 p = (char *)SMB_MALLOC(elsize);
700
701 if (!p) {
702 DEBUG(5,("array_promote: malloc fail\n"));
703 return;
704 }
705
706 memcpy(p,array + element * elsize, elsize);
707 memmove(array + elsize,array,elsize*element);
708 memcpy(array,p,elsize);
709 SAFE_FREE(p);
710}
711
712/*******************************************************************
713 Return the absolute current directory path - given a UNIX pathname.
714 Note that this path is returned in DOS format, not UNIX
715 format. Note this can be called with conn == NULL.
716********************************************************************/
717
718char *vfs_GetWd(connection_struct *conn, char *path)
719{
720 pstring s;
721 static BOOL getwd_cache_init = False;
722 SMB_STRUCT_STAT st, st2;
723 int i;
724
725 *s = 0;
726
727 if (!use_getwd_cache)
728 return(SMB_VFS_GETWD(conn,path));
729
730 /* init the cache */
731 if (!getwd_cache_init) {
732 getwd_cache_init = True;
733 for (i=0;i<MAX_GETWDCACHE;i++) {
734 string_set(&ino_list[i].dos_path,"");
735 ino_list[i].valid = False;
736 }
737 }
738
739 /* Get the inode of the current directory, if this doesn't work we're
740 in trouble :-) */
741
742 if (SMB_VFS_STAT(conn, ".",&st) == -1) {
743 /* Known to fail for root: the directory may be
744 * NFS-mounted and exported with root_squash (so has no root access). */
745 DEBUG(1,("vfs_GetWd: couldn't stat \".\" path=%s error %s (NFS problem ?)\n", path, strerror(errno) ));
746 return(SMB_VFS_GETWD(conn,path));
747 }
748
749
750 for (i=0; i<MAX_GETWDCACHE; i++) {
751 if (ino_list[i].valid) {
752
753 /* If we have found an entry with a matching inode and dev number
754 then find the inode number for the directory in the cached string.
755 If this agrees with that returned by the stat for the current
756 directory then all is o.k. (but make sure it is a directory all
757 the same...) */
758
759 if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
760 if (SMB_VFS_STAT(conn,ino_list[i].dos_path,&st2) == 0) {
761 if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
762 (st2.st_mode & S_IFMT) == S_IFDIR) {
763 pstrcpy (path, ino_list[i].dos_path);
764
765 /* promote it for future use */
766 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
767 return (path);
768 } else {
769 /* If the inode is different then something's changed,
770 scrub the entry and start from scratch. */
771 ino_list[i].valid = False;
772 }
773 }
774 }
775 }
776 }
777
778 /* We don't have the information to hand so rely on traditional methods.
779 The very slow getcwd, which spawns a process on some systems, or the
780 not quite so bad getwd. */
781
782 if (!SMB_VFS_GETWD(conn,s)) {
783 DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",strerror(errno)));
784 return (NULL);
785 }
786
787 pstrcpy(path,s);
788
789 DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
790
791 /* add it to the cache */
792 i = MAX_GETWDCACHE - 1;
793 string_set(&ino_list[i].dos_path,s);
794 ino_list[i].dev = st.st_dev;
795 ino_list[i].inode = st.st_ino;
796 ino_list[i].valid = True;
797
798 /* put it at the top of the list */
799 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
800
801 return (path);
802}
803
804/*******************************************************************
805 Reduce a file name, removing .. elements and checking that
806 it is below dir in the heirachy. This uses realpath.
807********************************************************************/
808
809NTSTATUS reduce_name(connection_struct *conn, const pstring fname)
810{
811#ifdef REALPATH_TAKES_NULL
812 BOOL free_resolved_name = True;
813#else
814#ifdef PATH_MAX
815 char resolved_name_buf[PATH_MAX+1];
816#else
817 pstring resolved_name_buf;
818#endif
819 BOOL free_resolved_name = False;
820#endif
821 char *resolved_name = NULL;
822 size_t con_path_len = strlen(conn->connectpath);
823 char *p = NULL;
824
825 DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
826
827#ifdef REALPATH_TAKES_NULL
828 resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
829#else
830 resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
831#endif
832
833 if (!resolved_name) {
834 switch (errno) {
835 case ENOTDIR:
836 DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
837 return map_nt_error_from_unix(errno);
838 case ENOENT:
839 {
840 pstring tmp_fname;
841 fstring last_component;
842 /* Last component didn't exist. Remove it and try and canonicalise the directory. */
843
844 pstrcpy(tmp_fname, fname);
845 p = strrchr_m(tmp_fname, '/');
846 if (p) {
847 *p++ = '\0';
848 fstrcpy(last_component, p);
849 } else {
850 fstrcpy(last_component, tmp_fname);
851 pstrcpy(tmp_fname, ".");
852 }
853
854#ifdef REALPATH_TAKES_NULL
855 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
856#else
857 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
858#endif
859 if (!resolved_name) {
860 DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
861 return map_nt_error_from_unix(errno);
862 }
863 pstrcpy(tmp_fname, resolved_name);
864 pstrcat(tmp_fname, "/");
865 pstrcat(tmp_fname, last_component);
866#ifdef REALPATH_TAKES_NULL
867 SAFE_FREE(resolved_name);
868 resolved_name = SMB_STRDUP(tmp_fname);
869 if (!resolved_name) {
870 DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
871 return NT_STATUS_NO_MEMORY;
872 }
873#else
874#ifdef PATH_MAX
875 safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
876#else
877 pstrcpy(resolved_name_buf, tmp_fname);
878#endif
879 resolved_name = resolved_name_buf;
880#endif
881 break;
882 }
883 default:
884 DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
885 return map_nt_error_from_unix(errno);
886 }
887 }
888
889 DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
890
891 if (*resolved_name != '/' && resolved_name[1] != ':') {
892 DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
893 if (free_resolved_name) {
894 SAFE_FREE(resolved_name);
895 }
896 return NT_STATUS_OBJECT_NAME_INVALID;
897 }
898
899 /* Check for widelinks allowed. */
900 if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) {
901 DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
902 if (free_resolved_name) {
903 SAFE_FREE(resolved_name);
904 }
905 return NT_STATUS_ACCESS_DENIED;
906 }
907
908 /* Check if we are allowing users to follow symlinks */
909 /* Patch from David Clerc <David.Clerc@cui.unige.ch>
910 University of Geneva */
911
912#ifdef S_ISLNK
913 if (!lp_symlinks(SNUM(conn))) {
914 SMB_STRUCT_STAT statbuf;
915 if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
916 (S_ISLNK(statbuf.st_mode)) ) {
917 if (free_resolved_name) {
918 SAFE_FREE(resolved_name);
919 }
920 DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
921 return NT_STATUS_ACCESS_DENIED;
922 }
923 }
924#endif
925
926 DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name));
927 if (free_resolved_name) {
928 SAFE_FREE(resolved_name);
929 }
930 return NT_STATUS_OK;
931}
Note: See TracBrowser for help on using the repository browser.