Implemented default ACL patch (set inherit acls = true on a per share basis).
[samba.git] / source3 / smbd / vfs-wrap.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Wrap disk only vfs functions to sidestep dodgy compilers.
4    Copyright (C) Tim Potter 1998
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22
23 /* Check for NULL pointer parameters in vfswrap_* functions */
24
25 #define VFS_CHECK_NULL
26
27 /* We don't want to have NULL function pointers lying around.  Someone
28    is sure to try and execute them.  These stubs are used to prevent
29    this possibility. */
30
31 int vfswrap_dummy_connect(connection_struct *conn, const char *service, const char *user)
32 {
33     return 0;    /* Return >= 0 for success */
34 }
35
36 void vfswrap_dummy_disconnect(connection_struct *conn)
37 {
38 }
39
40 /* Disk operations */
41
42 SMB_BIG_UINT vfswrap_disk_free(connection_struct *conn, const char *path, BOOL small_query, SMB_BIG_UINT *bsize, 
43                                SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
44 {
45     SMB_BIG_UINT result;
46
47 #ifdef VFS_CHECK_NULL
48     if ((path == NULL) || (bsize == NULL) || (dfree == NULL) ||
49         (dsize == NULL)) {
50         
51         smb_panic("NULL pointer passed to vfswrap_disk_free() function\n");
52     }
53 #endif
54
55     result = sys_disk_free(path, small_query, bsize, dfree, dsize);
56     return result;
57 }
58     
59 /* Directory operations */
60
61 DIR *vfswrap_opendir(connection_struct *conn, const char *fname)
62 {
63     DIR *result;
64
65     START_PROFILE(syscall_opendir);
66
67 #ifdef VFS_CHECK_NULL
68     if (fname == NULL) {
69         smb_panic("NULL pointer passed to vfswrap_opendir()\n");
70     }
71 #endif
72
73     result = opendir(fname);
74     END_PROFILE(syscall_opendir);
75     return result;
76 }
77
78 struct dirent *vfswrap_readdir(connection_struct *conn, DIR *dirp)
79 {
80     struct dirent *result;
81
82     START_PROFILE(syscall_readdir);
83
84 #ifdef VFS_CHECK_NULL
85     if (dirp == NULL) {
86         smb_panic("NULL pointer passed to vfswrap_readdir()\n");
87     }
88 #endif
89
90     result = readdir(dirp);
91     END_PROFILE(syscall_readdir);
92     return result;
93 }
94
95 int vfswrap_mkdir(connection_struct *conn, const char *path, mode_t mode)
96 {
97         int result;
98         BOOL has_dacl = False;
99
100         START_PROFILE(syscall_mkdir);
101
102 #ifdef VFS_CHECK_NULL
103         if (path == NULL) {
104                 smb_panic("NULL pointer passed to vfswrap_mkdir()\n");
105         }
106 #endif
107
108         if (lp_inherit_acls(SNUM(conn)) && (has_dacl = directory_has_default_acl(parent_dirname(path))))
109                 mode = 0777;
110
111         result = mkdir(path, mode);
112
113         if (result == 0 && !has_dacl) {
114                 /*
115                  * We need to do this as the default behavior of POSIX ACLs     
116                  * is to set the mask to be the requested group permission
117                  * bits, not the group permission bits to be the requested
118                  * group permission bits. This is not what we want, as it will
119                  * mess up any inherited ACL bits that were set. JRA.
120                  */
121                 int saved_errno = errno; /* We may get ENOSYS */
122                 if (conn->vfs_ops.chmod_acl != NULL) {
123                         if ((conn->vfs_ops.chmod_acl(conn, path, mode) == -1) && (errno == ENOSYS))
124                                 errno = saved_errno;
125                 }
126         }
127
128     END_PROFILE(syscall_mkdir);
129     return result;
130 }
131
132 int vfswrap_rmdir(connection_struct *conn, const char *path)
133 {
134     int result;
135
136     START_PROFILE(syscall_rmdir);
137
138 #ifdef VFS_CHECK_NULL
139     if (path == NULL) {
140         smb_panic("NULL pointer passed to vfswrap_rmdir()\n");
141     }
142 #endif
143
144     result = rmdir(path);
145     END_PROFILE(syscall_rmdir);
146     return result;
147 }
148
149 int vfswrap_closedir(connection_struct *conn, DIR *dirp)
150 {
151     int result;
152
153     START_PROFILE(syscall_closedir);
154
155 #ifdef VFS_CHECK_NULL
156     if (dirp == NULL) {
157         smb_panic("NULL pointer passed to vfswrap_closedir()\n");
158     }
159 #endif
160
161     result = closedir(dirp);
162     END_PROFILE(syscall_closedir);
163     return result;
164 }
165
166 /* File operations */
167     
168 int vfswrap_open(connection_struct *conn, const char *fname, int flags, mode_t mode)
169 {
170     int result;
171
172     START_PROFILE(syscall_open);
173
174 #ifdef VFS_CHECK_NULL
175     if (fname == NULL) {
176         smb_panic("NULL pointer passed to vfswrap_open()\n");
177     }
178 #endif
179
180     result = sys_open(fname, flags, mode);
181     END_PROFILE(syscall_open);
182     return result;
183 }
184
185 int vfswrap_close(files_struct *fsp, int fd)
186 {
187     int result;
188
189     START_PROFILE(syscall_close);
190
191     result = close(fd);
192     END_PROFILE(syscall_close);
193     return result;
194 }
195
196 ssize_t vfswrap_read(files_struct *fsp, int fd, void *data, size_t n)
197 {
198     ssize_t result;
199
200     START_PROFILE_BYTES(syscall_read, n);
201
202 #ifdef VFS_CHECK_NULL
203     if (data == NULL) {
204         smb_panic("NULL pointer passed to vfswrap_read()\n");
205     }
206 #endif
207
208     result = read(fd, data, n);
209     END_PROFILE(syscall_read);
210     return result;
211 }
212
213 ssize_t vfswrap_write(files_struct *fsp, int fd, const void *data, size_t n)
214 {
215     ssize_t result;
216
217     START_PROFILE_BYTES(syscall_write, n);
218
219 #ifdef VFS_CHECK_NULL
220     if (data == NULL) {
221         smb_panic("NULL pointer passed to vfswrap_write()\n");
222     }
223 #endif
224
225     result = write(fd, data, n);
226     END_PROFILE(syscall_write);
227     return result;
228 }
229
230 SMB_OFF_T vfswrap_lseek(files_struct *fsp, int filedes, SMB_OFF_T offset, int whence)
231 {
232         SMB_OFF_T result;
233
234         START_PROFILE(syscall_lseek);
235
236         result = sys_lseek(filedes, offset, whence);
237
238         /*
239          * We want to maintain the fiction that we can seek
240          * on a fifo for file system purposes. This allows
241          * people to set up UNIX fifo's that feed data to Windows
242          * applications. JRA.
243          */
244
245         if((result == -1) && (errno == ESPIPE)) {
246                 result = 0;
247                 errno = 0;
248         }
249
250         END_PROFILE(syscall_lseek);
251         return result;
252 }
253
254 int vfswrap_rename(connection_struct *conn, const char *old, const char *new)
255 {
256     int result;
257
258     START_PROFILE(syscall_rename);
259
260 #ifdef VFS_CHECK_NULL
261     if ((old == NULL) || (new == NULL)) {
262         smb_panic("NULL pointer passed to vfswrap_rename()\n");
263     }
264 #endif
265
266     result = rename(old, new);
267     END_PROFILE(syscall_rename);
268     return result;
269 }
270
271 int vfswrap_fsync(files_struct *fsp, int fd)
272 {
273 #ifdef HAVE_FSYNC
274     int result;
275
276     START_PROFILE(syscall_fsync);
277
278     result = fsync(fd);
279     END_PROFILE(syscall_fsync);
280     return result;
281 #else
282         return 0;
283 #endif
284 }
285
286 int vfswrap_stat(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *sbuf)
287 {
288     int result;
289
290     START_PROFILE(syscall_stat);
291
292 #ifdef VFS_CHECK_NULL
293     if ((fname == NULL) || (sbuf == NULL)) {
294         smb_panic("NULL pointer passed to vfswrap_stat()\n");
295     }
296 #endif
297
298     result = sys_stat(fname, sbuf);
299     END_PROFILE(syscall_stat);
300     return result;
301 }
302
303 int vfswrap_fstat(files_struct *fsp, int fd, SMB_STRUCT_STAT *sbuf)
304 {
305     int result;
306
307     START_PROFILE(syscall_fstat);
308
309 #ifdef VFS_CHECK_NULL
310     if (sbuf == NULL) {
311         smb_panic("NULL pointer passed to vfswrap_fstat()\n");
312     }
313 #endif
314
315     result = sys_fstat(fd, sbuf);
316     END_PROFILE(syscall_fstat);
317     return result;
318 }
319
320 int vfswrap_lstat(connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf)
321 {
322     int result;
323
324     START_PROFILE(syscall_lstat);
325
326 #ifdef VFS_CHECK_NULL
327     if ((path == NULL) || (sbuf == NULL)) {
328         smb_panic("NULL pointer passed to vfswrap_lstat()\n");
329     }
330 #endif
331
332     result = sys_lstat(path, sbuf);
333     END_PROFILE(syscall_lstat);
334     return result;
335 }
336
337 int vfswrap_unlink(connection_struct *conn, const char *path)
338 {
339     int result;
340
341     START_PROFILE(syscall_unlink);
342
343 #ifdef VFS_CHECK_NULL
344     if (path == NULL) {
345         smb_panic("NULL pointer passed to vfswrap_unlink()\n");
346     }
347 #endif
348
349     result = unlink(path);
350     END_PROFILE(syscall_unlink);
351     return result;
352 }
353
354 int vfswrap_chmod(connection_struct *conn, const char *path, mode_t mode)
355 {
356     int result;
357
358     START_PROFILE(syscall_chmod);
359
360 #ifdef VFS_CHECK_NULL
361     if (path == NULL) {
362         smb_panic("NULL pointer passed to vfswrap_chmod()\n");
363     }
364 #endif
365
366         /*
367          * We need to do this due to the fact that the default POSIX ACL
368          * chmod modifies the ACL *mask* for the group owner, not the
369          * group owner bits directly. JRA.
370          */
371
372         
373         if (conn->vfs_ops.chmod_acl != NULL) {
374                 int saved_errno = errno; /* We might get ENOSYS */
375                 if ((result = conn->vfs_ops.chmod_acl(conn, path, mode)) == 0) {
376                         END_PROFILE(syscall_chmod);
377                         return result;
378                 }
379                 /* Error - return the old errno. */
380                 errno = saved_errno;
381         }
382
383     result = chmod(path, mode);
384     END_PROFILE(syscall_chmod);
385     return result;
386 }
387
388 int vfswrap_fchmod(files_struct *fsp, int fd, mode_t mode)
389 {
390     int result;
391         struct vfs_ops *vfs_ops = &fsp->conn->vfs_ops;
392         
393     START_PROFILE(syscall_fchmod);
394
395         /*
396          * We need to do this due to the fact that the default POSIX ACL
397          * chmod modifies the ACL *mask* for the group owner, not the
398          * group owner bits directly. JRA.
399          */
400         
401         if (vfs_ops->fchmod_acl != NULL) {
402                 int saved_errno = errno; /* We might get ENOSYS */
403                 if ((result = vfs_ops->fchmod_acl(fsp, fd, mode)) == 0) {
404                         END_PROFILE(syscall_chmod);
405                         return result;
406                 }
407                 /* Error - return the old errno. */
408                 errno = saved_errno;
409         }
410
411     result = fchmod(fd, mode);
412     END_PROFILE(syscall_fchmod);
413     return result;
414 }
415
416 int vfswrap_chown(connection_struct *conn, const char *path, uid_t uid, gid_t gid)
417 {
418     int result;
419
420     START_PROFILE(syscall_chown);
421
422 #ifdef VFS_CHECK_NULL
423     if (path == NULL) {
424         smb_panic("NULL pointer passed to vfswrap_chown()\n");
425     }
426 #endif
427
428     result = sys_chown(path, uid, gid);
429     END_PROFILE(syscall_chown);
430     return result;
431 }
432
433 int vfswrap_fchown(files_struct *fsp, int fd, uid_t uid, gid_t gid)
434 {
435     int result;
436
437     START_PROFILE(syscall_fchown);
438
439     result = fchown(fd, uid, gid);
440     END_PROFILE(syscall_fchown);
441     return result;
442 }
443
444 int vfswrap_chdir(connection_struct *conn, const char *path)
445 {
446     int result;
447
448     START_PROFILE(syscall_chdir);
449
450 #ifdef VFS_CHECK_NULL
451     if (path == NULL) {
452         smb_panic("NULL pointer passed to vfswrap_chdir()\n");
453     }
454 #endif
455
456     result = chdir(path);
457     END_PROFILE(syscall_chdir);
458     return result;
459 }
460
461 char *vfswrap_getwd(connection_struct *conn, char *path)
462 {
463     char *result;
464
465     START_PROFILE(syscall_getwd);
466
467 #ifdef VFS_CHECK_NULL
468     if (path == NULL) {
469         smb_panic("NULL pointer passed to vfswrap_getwd()\n");
470     }
471 #endif
472
473     result = sys_getwd(path);
474     END_PROFILE(syscall_getwd);
475     return result;
476 }
477
478 int vfswrap_utime(connection_struct *conn, const char *path, struct utimbuf *times)
479 {
480     int result;
481
482     START_PROFILE(syscall_utime);
483
484 #ifdef VFS_CHECK_NULL
485     if ((path == NULL) || (times == NULL)) {
486         smb_panic("NULL pointer passed to vfswrap_utime()\n");
487     }
488 #endif
489
490     result = utime(path, times);
491     END_PROFILE(syscall_utime);
492     return result;
493 }
494
495 /*********************************************************************
496  A version of ftruncate that will write the space on disk if strict
497  allocate is set.
498 **********************************************************************/
499
500 static int strict_allocate_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len)
501 {
502         struct vfs_ops *vfs_ops = &fsp->conn->vfs_ops;
503         SMB_STRUCT_STAT st;
504         SMB_OFF_T currpos = vfs_ops->lseek(fsp, fd, 0, SEEK_CUR);
505         unsigned char zero_space[4096];
506         SMB_OFF_T space_to_write;
507
508         if (currpos == -1)
509                 return -1;
510
511         if (vfs_ops->fstat(fsp, fd, &st) == -1)
512                 return -1;
513
514         space_to_write = len - st.st_size;
515
516 #ifdef S_ISFIFO
517         if (S_ISFIFO(st.st_mode))
518                 return 0;
519 #endif
520
521         if (st.st_size == len)
522                 return 0;
523
524         /* Shrink - just ftruncate. */
525         if (st.st_size > len)
526                 return sys_ftruncate(fd, len);
527
528         /* Write out the real space on disk. */
529         if (vfs_ops->lseek(fsp, fd, st.st_size, SEEK_SET) != st.st_size)
530                 return -1;
531
532         space_to_write = len - st.st_size;
533
534         memset(zero_space, '\0', sizeof(zero_space));
535         while ( space_to_write > 0) {
536                 SMB_OFF_T retlen;
537                 SMB_OFF_T current_len_to_write = MIN(sizeof(zero_space),space_to_write);
538
539                 retlen = vfs_ops->write(fsp,fsp->fd,(char *)zero_space,current_len_to_write);
540                 if (retlen <= 0)
541                         return -1;
542
543                 space_to_write -= retlen;
544         }
545
546         /* Seek to where we were */
547         if (vfs_ops->lseek(fsp, fd, currpos, SEEK_SET) != currpos)
548                 return -1;
549
550         return 0;
551 }
552
553 int vfswrap_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len)
554 {
555         int result = -1;
556         struct vfs_ops *vfs_ops = &fsp->conn->vfs_ops;
557         SMB_STRUCT_STAT st;
558         char c = 0;
559         SMB_OFF_T currpos;
560
561         START_PROFILE(syscall_ftruncate);
562
563         if (lp_strict_allocate(SNUM(fsp->conn))) {
564                 result = strict_allocate_ftruncate(fsp, fd, len);
565                 END_PROFILE(syscall_ftruncate);
566                 return result;
567         }
568
569         /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
570            sys_ftruncate if the system supports it. Then I discovered that
571            you can have some filesystems that support ftruncate
572            expansion and some that don't! On Linux fat can't do
573            ftruncate extend but ext2 can. */
574
575         result = sys_ftruncate(fd, len);
576         if (result == 0)
577                 goto done;
578
579         /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
580            extend a file with ftruncate. Provide alternate implementation
581            for this */
582         currpos = vfs_ops->lseek(fsp, fd, 0, SEEK_CUR);
583         if (currpos == -1) {
584                 goto done;
585         }
586
587         /* Do an fstat to see if the file is longer than the requested
588            size in which case the ftruncate above should have
589            succeeded or shorter, in which case seek to len - 1 and
590            write 1 byte of zero */
591         if (vfs_ops->fstat(fsp, fd, &st) == -1) {
592                 goto done;
593         }
594
595 #ifdef S_ISFIFO
596         if (S_ISFIFO(st.st_mode)) {
597                 result = 0;
598                 goto done;
599         }
600 #endif
601
602         if (st.st_size == len) {
603                 result = 0;
604                 goto done;
605         }
606
607         if (st.st_size > len) {
608                 /* the sys_ftruncate should have worked */
609                 goto done;
610         }
611
612         if (vfs_ops->lseek(fsp, fd, len-1, SEEK_SET) != len -1)
613                 goto done;
614
615         if (vfs_ops->write(fsp, fd, &c, 1)!=1)
616                 goto done;
617
618         /* Seek to where we were */
619         if (vfs_ops->lseek(fsp, fd, currpos, SEEK_SET) != currpos)
620                 goto done;
621         result = 0;
622
623   done:
624
625         END_PROFILE(syscall_ftruncate);
626         return result;
627 }
628
629 BOOL vfswrap_lock(files_struct *fsp, int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
630 {
631     BOOL result;
632
633     START_PROFILE(syscall_fcntl_lock);
634
635     result =  fcntl_lock(fd, op, offset, count,type);
636     END_PROFILE(syscall_fcntl_lock);
637     return result;
638 }
639
640 int vfswrap_symlink(connection_struct *conn, const char *oldpath, const char *newpath)
641 {
642     int result;
643
644     START_PROFILE(syscall_symlink);
645
646 #ifdef VFS_CHECK_NULL
647     if ((oldpath == NULL) || (newpath == NULL))
648                 smb_panic("NULL pointer passed to vfswrap_symlink()\n");
649 #endif
650
651     result = sys_symlink(oldpath, newpath);
652     END_PROFILE(syscall_symlink);
653     return result;
654 }
655
656 int vfswrap_readlink(connection_struct *conn, const char *path, char *buf, size_t bufsiz)
657 {
658     int result;
659
660     START_PROFILE(syscall_readlink);
661
662 #ifdef VFS_CHECK_NULL
663     if ((path == NULL) || (buf == NULL))
664                 smb_panic("NULL pointer passed to vfswrap_readlink()\n");
665 #endif
666
667     result = sys_readlink(path, buf, bufsiz);
668     END_PROFILE(syscall_readlink);
669     return result;
670 }
671
672 int vfswrap_link(connection_struct *conn, const char *oldpath, const char *newpath)
673 {
674         int result;
675
676         START_PROFILE(syscall_link);
677
678 #ifdef VFS_CHECK_NULL
679         if ((oldpath == NULL) || (newpath == NULL))
680                 smb_panic("NULL pointer passed to vfswrap_link()\n");
681 #endif
682         result = sys_link(oldpath, newpath);
683         END_PROFILE(syscall_link);
684         return result;
685 }
686
687 int vfswrap_mknod(connection_struct *conn, const char *pathname, mode_t mode, SMB_DEV_T dev)
688 {
689         int result;
690
691         START_PROFILE(syscall_mknod);
692
693 #ifdef VFS_CHECK_NULL
694         if (pathname == NULL)
695                 smb_panic("NULL pointer passed to vfswrap_mknod()\n");
696 #endif
697         result = sys_mknod(pathname, mode, dev);
698         END_PROFILE(syscall_mknod);
699         return result;
700 }
701
702 size_t vfswrap_fget_nt_acl(files_struct *fsp, int fd, SEC_DESC **ppdesc)
703 {
704         size_t result;
705
706         START_PROFILE(fget_nt_acl);
707         result = get_nt_acl(fsp, ppdesc);
708         END_PROFILE(fget_nt_acl);
709         return result;
710 }
711
712 size_t vfswrap_get_nt_acl(files_struct *fsp, const char *name, SEC_DESC **ppdesc)
713 {
714         size_t result;
715
716         START_PROFILE(get_nt_acl);
717         result = get_nt_acl(fsp, ppdesc);
718         END_PROFILE(get_nt_acl);
719         return result;
720 }
721
722 BOOL vfswrap_fset_nt_acl(files_struct *fsp, int fd, uint32 security_info_sent, SEC_DESC *psd)
723 {
724         BOOL result;
725
726         START_PROFILE(fset_nt_acl);
727         result = set_nt_acl(fsp, security_info_sent, psd);
728         END_PROFILE(fset_nt_acl);
729         return result;
730 }
731
732 BOOL vfswrap_set_nt_acl(files_struct *fsp, const char *name, uint32 security_info_sent, SEC_DESC *psd)
733 {
734         BOOL result;
735
736         START_PROFILE(set_nt_acl);
737         result = set_nt_acl(fsp, security_info_sent, psd);
738         END_PROFILE(set_nt_acl);
739         return result;
740 }
741
742 int vfswrap_chmod_acl(connection_struct *conn, const char *name, mode_t mode)
743 {
744         int result;
745
746         START_PROFILE(chmod_acl);
747         result = chmod_acl(name, mode);
748         END_PROFILE(chmod_acl);
749         return result;
750 }
751
752 int vfswrap_fchmod_acl(files_struct *fsp, int fd, mode_t mode)
753 {
754         int result;
755
756         START_PROFILE(fchmod_acl);
757         result = fchmod_acl(fd, mode);
758         END_PROFILE(fchmod_acl);
759         return result;
760 }