s3 oplocks: Make the level2 oplock contention API more granular
[sfrench/samba-autobuild/.git] / source3 / smbd / vfs.c
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 3 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, see <http://www.gnu.org/licenses/>.
21
22    This work was sponsored by Optifacio Software Services, Inc.
23 */
24
25 #include "includes.h"
26 #include "smbd/globals.h"
27
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_VFS
30
31 static_decl_vfs;
32
33 struct vfs_init_function_entry {
34         char *name;
35         const vfs_op_tuple *vfs_op_tuples;
36         struct vfs_init_function_entry *prev, *next;
37 };
38
39 /****************************************************************************
40     maintain the list of available backends
41 ****************************************************************************/
42
43 static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name)
44 {
45         struct vfs_init_function_entry *entry = backends;
46
47         DEBUG(10, ("vfs_find_backend_entry called for %s\n", name));
48  
49         while(entry) {
50                 if (strcmp(entry->name, name)==0) return entry;
51                 entry = entry->next;
52         }
53
54         return NULL;
55 }
56
57 NTSTATUS smb_register_vfs(int version, const char *name, const 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
93 static 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
103 static 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
110 bool vfs_init_custom(connection_struct *conn, const char *vfs_object)
111 {
112         const vfs_op_tuple *ops;
113         char *module_path = NULL;
114         char *module_name = NULL;
115         char *module_param = NULL, *p;
116         int i;
117         vfs_handle_struct *handle;
118         const struct vfs_init_function_entry *entry;
119         
120         if (!conn||!vfs_object||!vfs_object[0]) {
121                 DEBUG(0,("vfs_init_custon() called with NULL pointer or emtpy vfs_object!\n"));
122                 return False;
123         }
124
125         if(!backends) {
126                 static_init_vfs;
127         }
128
129         DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object));
130
131         module_path = smb_xstrdup(vfs_object);
132
133         p = strchr_m(module_path, ':');
134
135         if (p) {
136                 *p = 0;
137                 module_param = p+1;
138                 trim_char(module_param, ' ', ' ');
139         }
140
141         trim_char(module_path, ' ', ' ');
142
143         module_name = smb_xstrdup(module_path);
144
145         if ((module_name[0] == '/') &&
146             (strcmp(module_path, DEFAULT_VFS_MODULE_NAME) != 0)) {
147
148                 /*
149                  * Extract the module name from the path. Just use the base
150                  * name of the last path component.
151                  */
152
153                 SAFE_FREE(module_name);
154                 module_name = smb_xstrdup(strrchr_m(module_path, '/')+1);
155
156                 p = strchr_m(module_name, '.');
157
158                 if (p != NULL) {
159                         *p = '\0';
160                 }
161         }
162
163         /* First, try to load the module with the new module system */
164         if((entry = vfs_find_backend_entry(module_name)) || 
165            (NT_STATUS_IS_OK(smb_probe_module("vfs", module_path)) &&
166                 (entry = vfs_find_backend_entry(module_name)))) {
167
168                 DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
169                 
170                 if ((ops = entry->vfs_op_tuples) == NULL) {
171                         DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object));
172                         goto fail;
173                 }
174         } else {
175                 DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
176                 goto fail;
177         }
178
179         handle = TALLOC_ZERO_P(conn, vfs_handle_struct);
180         if (!handle) {
181                 DEBUG(0,("TALLOC_ZERO() failed!\n"));
182                 goto fail;
183         }
184         memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops));
185         handle->conn = conn;
186         if (module_param) {
187                 handle->param = talloc_strdup(conn, module_param);
188         }
189         DLIST_ADD(conn->vfs_handles, handle);
190
191         for(i=0; ops[i].op != NULL; i++) {
192                 DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer));
193                 if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) {
194                         /* If this operation was already made opaque by different module, it
195                          * will be overridden here.
196                          */
197                         DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object));
198                         vfs_set_operation(&conn->vfs_opaque, ops[i].type, handle, ops[i].op);
199                 }
200                 /* Change current VFS disposition*/
201                 DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object));
202                 vfs_set_operation(&conn->vfs, ops[i].type, handle, ops[i].op);
203         }
204
205         SAFE_FREE(module_path);
206         SAFE_FREE(module_name);
207         return True;
208
209  fail:
210         SAFE_FREE(module_path);
211         SAFE_FREE(module_name);
212         return False;
213 }
214
215 /*****************************************************************
216  Allow VFS modules to extend files_struct with VFS-specific state.
217  This will be ok for small numbers of extensions, but might need to
218  be refactored if it becomes more widely used.
219 ******************************************************************/
220
221 #define EXT_DATA_AREA(e) ((uint8 *)(e) + sizeof(struct vfs_fsp_data))
222
223 void *vfs_add_fsp_extension_notype(vfs_handle_struct *handle,
224                                    files_struct *fsp, size_t ext_size,
225                                    void (*destroy_fn)(void *p_data))
226 {
227         struct vfs_fsp_data *ext;
228         void * ext_data;
229
230         /* Prevent VFS modules adding multiple extensions. */
231         if ((ext_data = vfs_fetch_fsp_extension(handle, fsp))) {
232                 return ext_data;
233         }
234
235         ext = (struct vfs_fsp_data *)TALLOC_ZERO(
236                 handle->conn, sizeof(struct vfs_fsp_data) + ext_size);
237         if (ext == NULL) {
238                 return NULL;
239         }
240
241         ext->owner = handle;
242         ext->next = fsp->vfs_extension;
243         ext->destroy = destroy_fn;
244         fsp->vfs_extension = ext;
245         return EXT_DATA_AREA(ext);
246 }
247
248 void vfs_remove_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
249 {
250         struct vfs_fsp_data *curr;
251         struct vfs_fsp_data *prev;
252
253         for (curr = fsp->vfs_extension, prev = NULL;
254              curr;
255              prev = curr, curr = curr->next) {
256                 if (curr->owner == handle) {
257                     if (prev) {
258                             prev->next = curr->next;
259                     } else {
260                             fsp->vfs_extension = curr->next;
261                     }
262                     if (curr->destroy) {
263                             curr->destroy(EXT_DATA_AREA(curr));
264                     }
265                     TALLOC_FREE(curr);
266                     return;
267                 }
268         }
269 }
270
271 void *vfs_memctx_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
272 {
273         struct vfs_fsp_data *head;
274
275         for (head = fsp->vfs_extension; head; head = head->next) {
276                 if (head->owner == handle) {
277                         return head;
278                 }
279         }
280
281         return NULL;
282 }
283
284 void *vfs_fetch_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
285 {
286         struct vfs_fsp_data *head;
287
288         head = (struct vfs_fsp_data *)vfs_memctx_fsp_extension(handle, fsp);
289         if (head != NULL) {
290                 return EXT_DATA_AREA(head);
291         }
292
293         return NULL;
294 }
295
296 #undef EXT_DATA_AREA
297
298 /*****************************************************************
299  Generic VFS init.
300 ******************************************************************/
301
302 bool 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
333 bool 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  Check if an object exists in the vfs.
353 ********************************************************************/
354
355 bool vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
356 {
357         SMB_STRUCT_STAT st;
358
359         if (!sbuf)
360                 sbuf = &st;
361
362         ZERO_STRUCTP(sbuf);
363
364         if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
365                 return(False);
366         return True;
367 }
368
369 /*******************************************************************
370  Check if a file exists in the vfs.
371 ********************************************************************/
372
373 bool vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
374 {
375         SMB_STRUCT_STAT st;
376
377         if (!sbuf)
378                 sbuf = &st;
379
380         ZERO_STRUCTP(sbuf);
381
382         if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
383                 return False;
384         return(S_ISREG(sbuf->st_mode));
385 }
386
387 /****************************************************************************
388  Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
389 ****************************************************************************/
390
391 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
392 {
393         size_t total=0;
394
395         while (total < byte_count)
396         {
397                 ssize_t ret = SMB_VFS_READ(fsp, buf + total,
398                                            byte_count - total);
399
400                 if (ret == 0) return total;
401                 if (ret == -1) {
402                         if (errno == EINTR)
403                                 continue;
404                         else
405                                 return -1;
406                 }
407                 total += ret;
408         }
409         return (ssize_t)total;
410 }
411
412 ssize_t vfs_pread_data(files_struct *fsp, char *buf,
413                 size_t byte_count, SMB_OFF_T offset)
414 {
415         size_t total=0;
416
417         while (total < byte_count)
418         {
419                 ssize_t ret = SMB_VFS_PREAD(fsp, buf + total,
420                                         byte_count - total, offset + total);
421
422                 if (ret == 0) return total;
423                 if (ret == -1) {
424                         if (errno == EINTR)
425                                 continue;
426                         else
427                                 return -1;
428                 }
429                 total += ret;
430         }
431         return (ssize_t)total;
432 }
433
434 /****************************************************************************
435  Write data to a fd on the vfs.
436 ****************************************************************************/
437
438 ssize_t vfs_write_data(struct smb_request *req,
439                         files_struct *fsp,
440                         const char *buffer,
441                         size_t N)
442 {
443         size_t total=0;
444         ssize_t ret;
445
446         if (req && req->unread_bytes) {
447                 SMB_ASSERT(req->unread_bytes == N);
448                 /* VFS_RECVFILE must drain the socket
449                  * before returning. */
450                 req->unread_bytes = 0;
451                 return SMB_VFS_RECVFILE(smbd_server_fd(),
452                                         fsp,
453                                         (SMB_OFF_T)-1,
454                                         N);
455         }
456
457         while (total < N) {
458                 ret = SMB_VFS_WRITE(fsp, buffer + total, N - total);
459
460                 if (ret == -1)
461                         return -1;
462                 if (ret == 0)
463                         return total;
464
465                 total += ret;
466         }
467         return (ssize_t)total;
468 }
469
470 ssize_t vfs_pwrite_data(struct smb_request *req,
471                         files_struct *fsp,
472                         const char *buffer,
473                         size_t N,
474                         SMB_OFF_T offset)
475 {
476         size_t total=0;
477         ssize_t ret;
478
479         if (req && req->unread_bytes) {
480                 SMB_ASSERT(req->unread_bytes == N);
481                 /* VFS_RECVFILE must drain the socket
482                  * before returning. */
483                 req->unread_bytes = 0;
484                 return SMB_VFS_RECVFILE(smbd_server_fd(),
485                                         fsp,
486                                         offset,
487                                         N);
488         }
489
490         while (total < N) {
491                 ret = SMB_VFS_PWRITE(fsp, buffer + total, N - total,
492                                      offset + total);
493
494                 if (ret == -1)
495                         return -1;
496                 if (ret == 0)
497                         return total;
498
499                 total += ret;
500         }
501         return (ssize_t)total;
502 }
503 /****************************************************************************
504  An allocate file space call using the vfs interface.
505  Allocates space for a file from a filedescriptor.
506  Returns 0 on success, -1 on failure.
507 ****************************************************************************/
508
509 int vfs_allocate_file_space(files_struct *fsp, uint64_t len)
510 {
511         int ret;
512         SMB_STRUCT_STAT st;
513         connection_struct *conn = fsp->conn;
514         uint64_t space_avail;
515         uint64_t bsize,dfree,dsize;
516
517         /*
518          * Actually try and commit the space on disk....
519          */
520
521         DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
522
523         if (((SMB_OFF_T)len) < 0) {
524                 DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
525                 errno = EINVAL;
526                 return -1;
527         }
528
529         ret = SMB_VFS_FSTAT(fsp, &st);
530         if (ret == -1)
531                 return ret;
532
533         if (len == (uint64_t)st.st_size)
534                 return 0;
535
536         if (len < (uint64_t)st.st_size) {
537                 /* Shrink - use ftruncate. */
538
539                 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
540                                 fsp->fsp_name, (double)st.st_size ));
541
542                 contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_ALLOC_SHRINK);
543
544                 flush_write_cache(fsp, SIZECHANGE_FLUSH);
545                 if ((ret = SMB_VFS_FTRUNCATE(fsp, (SMB_OFF_T)len)) != -1) {
546                         set_filelen_write_cache(fsp, len);
547                 }
548
549                 contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_ALLOC_SHRINK);
550
551                 return ret;
552         }
553
554         /* Grow - we need to test if we have enough space. */
555
556         contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_ALLOC_GROW);
557         contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_ALLOC_GROW);
558
559         if (!lp_strict_allocate(SNUM(fsp->conn)))
560                 return 0;
561
562         len -= st.st_size;
563         len /= 1024; /* Len is now number of 1k blocks needed. */
564         space_avail = get_dfree_info(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
565         if (space_avail == (uint64_t)-1) {
566                 return -1;
567         }
568
569         DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
570                         fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
571
572         if (len > space_avail) {
573                 errno = ENOSPC;
574                 return -1;
575         }
576
577         return 0;
578 }
579
580 /****************************************************************************
581  A vfs set_filelen call.
582  set the length of a file from a filedescriptor.
583  Returns 0 on success, -1 on failure.
584 ****************************************************************************/
585
586 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
587 {
588         int ret;
589
590         contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_SET_FILE_LEN);
591
592         DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
593         flush_write_cache(fsp, SIZECHANGE_FLUSH);
594         if ((ret = SMB_VFS_FTRUNCATE(fsp, len)) != -1) {
595                 set_filelen_write_cache(fsp, len);
596                 notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
597                              FILE_NOTIFY_CHANGE_SIZE
598                              | FILE_NOTIFY_CHANGE_ATTRIBUTES,
599                              fsp->fsp_name);
600         }
601
602         contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_SET_FILE_LEN);
603
604         return ret;
605 }
606
607 /****************************************************************************
608  A vfs fill sparse call.
609  Writes zeros from the end of file to len, if len is greater than EOF.
610  Used only by strict_sync.
611  Returns 0 on success, -1 on failure.
612 ****************************************************************************/
613
614 #define SPARSE_BUF_WRITE_SIZE (32*1024)
615
616 int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
617 {
618         int ret;
619         SMB_STRUCT_STAT st;
620         SMB_OFF_T offset;
621         size_t total;
622         size_t num_to_write;
623         ssize_t pwrite_ret;
624
625         ret = SMB_VFS_FSTAT(fsp, &st);
626         if (ret == -1) {
627                 return ret;
628         }
629
630         if (len <= st.st_size) {
631                 return 0;
632         }
633
634         DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to len %.0f (%.0f bytes)\n",
635                 fsp->fsp_name, (double)st.st_size, (double)len, (double)(len - st.st_size)));
636
637         contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_FILL_SPARSE);
638
639         flush_write_cache(fsp, SIZECHANGE_FLUSH);
640
641         if (!sparse_buf) {
642                 sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE);
643                 if (!sparse_buf) {
644                         errno = ENOMEM;
645                         ret = -1;
646                         goto out;
647                 }
648         }
649
650         offset = st.st_size;
651         num_to_write = len - st.st_size;
652         total = 0;
653
654         while (total < num_to_write) {
655                 size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (num_to_write - total));
656
657                 pwrite_ret = SMB_VFS_PWRITE(fsp, sparse_buf, curr_write_size, offset + total);
658                 if (pwrite_ret == -1) {
659                         DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s\n",
660                                 fsp->fsp_name, strerror(errno) ));
661                         ret = -1;
662                         goto out;
663                 }
664                 if (pwrite_ret == 0) {
665                         ret = 0;
666                         goto out;
667                 }
668
669                 total += pwrite_ret;
670         }
671
672         set_filelen_write_cache(fsp, len);
673
674         ret = 0;
675  out:
676         contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_FILL_SPARSE);
677         return ret;
678 }
679
680 /****************************************************************************
681  Transfer some data (n bytes) between two file_struct's.
682 ****************************************************************************/
683
684 static ssize_t vfs_read_fn(void *file, void *buf, size_t len)
685 {
686         struct files_struct *fsp = (struct files_struct *)file;
687
688         return SMB_VFS_READ(fsp, buf, len);
689 }
690
691 static ssize_t vfs_write_fn(void *file, const void *buf, size_t len)
692 {
693         struct files_struct *fsp = (struct files_struct *)file;
694
695         return SMB_VFS_WRITE(fsp, buf, len);
696 }
697
698 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
699 {
700         return transfer_file_internal((void *)in, (void *)out, n,
701                                       vfs_read_fn, vfs_write_fn);
702 }
703
704 /*******************************************************************
705  A vfs_readdir wrapper which just returns the file name.
706 ********************************************************************/
707
708 char *vfs_readdirname(connection_struct *conn, void *p)
709 {
710         SMB_STRUCT_DIRENT *ptr= NULL;
711         char *dname;
712
713         if (!p)
714                 return(NULL);
715
716         ptr = SMB_VFS_READDIR(conn, (DIR *)p);
717         if (!ptr)
718                 return(NULL);
719
720         dname = ptr->d_name;
721
722 #ifdef NEXT2
723         if (telldir(p) < 0)
724                 return(NULL);
725 #endif
726
727 #ifdef HAVE_BROKEN_READDIR_NAME
728         /* using /usr/ucb/cc is BAD */
729         dname = dname - 2;
730 #endif
731
732         return(dname);
733 }
734
735 /*******************************************************************
736  A wrapper for vfs_chdir().
737 ********************************************************************/
738
739 int vfs_ChDir(connection_struct *conn, const char *path)
740 {
741         int res;
742
743         if (!LastDir) {
744                 LastDir = SMB_STRDUP("");
745         }
746
747         if (strcsequal(path,"."))
748                 return(0);
749
750         if (*path == '/' && strcsequal(LastDir,path))
751                 return(0);
752
753         DEBUG(4,("vfs_ChDir to %s\n",path));
754
755         res = SMB_VFS_CHDIR(conn,path);
756         if (!res) {
757                 SAFE_FREE(LastDir);
758                 LastDir = SMB_STRDUP(path);
759         }
760         return(res);
761 }
762
763 /*******************************************************************
764  Return the absolute current directory path - given a UNIX pathname.
765  Note that this path is returned in DOS format, not UNIX
766  format. Note this can be called with conn == NULL.
767 ********************************************************************/
768
769 struct getwd_cache_key {
770         SMB_DEV_T dev;
771         SMB_INO_T ino;
772 };
773
774 char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn)
775 {
776         char s[PATH_MAX+1];
777         SMB_STRUCT_STAT st, st2;
778         char *result;
779         DATA_BLOB cache_value;
780         struct getwd_cache_key key;
781
782         *s = 0;
783
784         if (!lp_getwd_cache()) {
785                 goto nocache;
786         }
787
788         SET_STAT_INVALID(st);
789
790         if (SMB_VFS_STAT(conn, ".",&st) == -1) {
791                 /*
792                  * Known to fail for root: the directory may be NFS-mounted
793                  * and exported with root_squash (so has no root access).
794                  */
795                 DEBUG(1,("vfs_GetWd: couldn't stat \".\" error %s "
796                          "(NFS problem ?)\n", strerror(errno) ));
797                 goto nocache;
798         }
799
800         ZERO_STRUCT(key); /* unlikely, but possible padding */
801         key.dev = st.st_dev;
802         key.ino = st.st_ino;
803
804         if (!memcache_lookup(smbd_memcache(), GETWD_CACHE,
805                              data_blob_const(&key, sizeof(key)),
806                              &cache_value)) {
807                 goto nocache;
808         }
809
810         SMB_ASSERT((cache_value.length > 0)
811                    && (cache_value.data[cache_value.length-1] == '\0'));
812
813         if ((SMB_VFS_STAT(conn, (char *)cache_value.data, &st2) == 0)
814             && (st.st_dev == st2.st_dev) && (st.st_ino == st2.st_ino)
815             && (S_ISDIR(st.st_mode))) {
816                 /*
817                  * Ok, we're done
818                  */
819                 result = talloc_strdup(ctx, (char *)cache_value.data);
820                 if (result == NULL) {
821                         errno = ENOMEM;
822                 }
823                 return result;
824         }
825
826  nocache:
827
828         /*
829          * We don't have the information to hand so rely on traditional
830          * methods. The very slow getcwd, which spawns a process on some
831          * systems, or the not quite so bad getwd.
832          */
833
834         if (!SMB_VFS_GETWD(conn,s)) {
835                 DEBUG(0, ("vfs_GetWd: SMB_VFS_GETWD call failed: %s\n",
836                           strerror(errno)));
837                 return NULL;
838         }
839
840         if (lp_getwd_cache() && VALID_STAT(st)) {
841                 ZERO_STRUCT(key); /* unlikely, but possible padding */
842                 key.dev = st.st_dev;
843                 key.ino = st.st_ino;
844
845                 memcache_add(smbd_memcache(), GETWD_CACHE,
846                              data_blob_const(&key, sizeof(key)),
847                              data_blob_const(s, strlen(s)+1));
848         }
849
850         result = talloc_strdup(ctx, s);
851         if (result == NULL) {
852                 errno = ENOMEM;
853         }
854         return result;
855 }
856
857 /*******************************************************************
858  Reduce a file name, removing .. elements and checking that
859  it is below dir in the heirachy. This uses realpath.
860 ********************************************************************/
861
862 NTSTATUS check_reduced_name(connection_struct *conn, const char *fname)
863 {
864 #ifdef REALPATH_TAKES_NULL
865         bool free_resolved_name = True;
866 #else
867         char resolved_name_buf[PATH_MAX+1];
868         bool free_resolved_name = False;
869 #endif
870         char *resolved_name = NULL;
871         size_t con_path_len = strlen(conn->connectpath);
872         char *p = NULL;
873
874         DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
875
876 #ifdef REALPATH_TAKES_NULL
877         resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
878 #else
879         resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
880 #endif
881
882         if (!resolved_name) {
883                 switch (errno) {
884                         case ENOTDIR:
885                                 DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
886                                 return map_nt_error_from_unix(errno);
887                         case ENOENT:
888                         {
889                                 TALLOC_CTX *ctx = talloc_tos();
890                                 char *tmp_fname = NULL;
891                                 char *last_component = NULL;
892                                 /* Last component didn't exist. Remove it and try and canonicalise the directory. */
893
894                                 tmp_fname = talloc_strdup(ctx, fname);
895                                 if (!tmp_fname) {
896                                         return NT_STATUS_NO_MEMORY;
897                                 }
898                                 p = strrchr_m(tmp_fname, '/');
899                                 if (p) {
900                                         *p++ = '\0';
901                                         last_component = p;
902                                 } else {
903                                         last_component = tmp_fname;
904                                         tmp_fname = talloc_strdup(ctx,
905                                                         ".");
906                                         if (!tmp_fname) {
907                                                 return NT_STATUS_NO_MEMORY;
908                                         }
909                                 }
910
911 #ifdef REALPATH_TAKES_NULL
912                                 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
913 #else
914                                 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
915 #endif
916                                 if (!resolved_name) {
917                                         DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
918                                         return map_nt_error_from_unix(errno);
919                                 }
920                                 tmp_fname = talloc_asprintf(ctx,
921                                                 "%s/%s",
922                                                 resolved_name,
923                                                 last_component);
924                                 if (!tmp_fname) {
925                                         return NT_STATUS_NO_MEMORY;
926                                 }
927 #ifdef REALPATH_TAKES_NULL
928                                 SAFE_FREE(resolved_name);
929                                 resolved_name = SMB_STRDUP(tmp_fname);
930                                 if (!resolved_name) {
931                                         DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
932                                         return NT_STATUS_NO_MEMORY;
933                                 }
934 #else
935                                 safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
936                                 resolved_name = resolved_name_buf;
937 #endif
938                                 break;
939                         }
940                         default:
941                                 DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
942                                 return map_nt_error_from_unix(errno);
943                 }
944         }
945
946         DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
947
948         if (*resolved_name != '/') {
949                 DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
950                 if (free_resolved_name) {
951                         SAFE_FREE(resolved_name);
952                 }
953                 return NT_STATUS_OBJECT_NAME_INVALID;
954         }
955
956         /* Check for widelinks allowed. */
957         if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) {
958                 DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
959                 if (free_resolved_name) {
960                         SAFE_FREE(resolved_name);
961                 }
962                 return NT_STATUS_ACCESS_DENIED;
963         }
964
965         /* Check if we are allowing users to follow symlinks */
966         /* Patch from David Clerc <David.Clerc@cui.unige.ch>
967                 University of Geneva */
968
969 #ifdef S_ISLNK
970         if (!lp_symlinks(SNUM(conn))) {
971                 SMB_STRUCT_STAT statbuf;
972                 if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
973                                 (S_ISLNK(statbuf.st_mode)) ) {
974                         if (free_resolved_name) {
975                                 SAFE_FREE(resolved_name);
976                         }
977                         DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
978                         return NT_STATUS_ACCESS_DENIED;
979                 }
980         }
981 #endif
982
983         DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name));
984         if (free_resolved_name) {
985                 SAFE_FREE(resolved_name);
986         }
987         return NT_STATUS_OK;
988 }