s3:smbd: move pending_auth_data list to struct smbd_server_connection
[kai/samba.git] / source3 / smbd / vfs.c
index 011f31dd24c531d698ede308bea6ee90c1a040d7..873e65e4a4a0b56901142ee6cfa0a09bf5f722a6 100644 (file)
@@ -23,6 +23,7 @@
 */
 
 #include "includes.h"
+#include "smbd/globals.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_VFS
@@ -35,8 +36,6 @@ struct vfs_init_function_entry {
        struct vfs_init_function_entry *prev, *next;
 };
 
-static struct vfs_init_function_entry *backends = NULL;
-
 /****************************************************************************
     maintain the list of available backends
 ****************************************************************************/
@@ -162,18 +161,30 @@ bool vfs_init_custom(connection_struct *conn, const char *vfs_object)
        }
 
        /* First, try to load the module with the new module system */
-       if((entry = vfs_find_backend_entry(module_name)) || 
-          (NT_STATUS_IS_OK(smb_probe_module("vfs", module_path)) &&
-               (entry = vfs_find_backend_entry(module_name)))) {
-
-               DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
-               
-               if ((ops = entry->vfs_op_tuples) == NULL) {
-                       DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object));
+       entry = vfs_find_backend_entry(module_name);
+       if (!entry) {
+               NTSTATUS status;
+
+               DEBUG(5, ("vfs module [%s] not loaded - trying to load...\n",
+                         vfs_object));
+
+               status = smb_probe_module("vfs", module_path);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0, ("error probing vfs module '%s': %s\n",
+                                 module_path, nt_errstr(status)));
+                       goto fail;
+               }
+
+               entry = vfs_find_backend_entry(module_name);
+               if (!entry) {
+                       DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
                        goto fail;
-               }
-       } else {
-               DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
+               }
+       }
+
+       DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
+       if ((ops = entry->vfs_op_tuples) == NULL) {
+               DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object));
                goto fail;
        }
 
@@ -221,7 +232,9 @@ bool vfs_init_custom(connection_struct *conn, const char *vfs_object)
 
 #define EXT_DATA_AREA(e) ((uint8 *)(e) + sizeof(struct vfs_fsp_data))
 
-void *vfs_add_fsp_extension_notype(vfs_handle_struct *handle, files_struct *fsp, size_t ext_size)
+void *vfs_add_fsp_extension_notype(vfs_handle_struct *handle,
+                                  files_struct *fsp, size_t ext_size,
+                                  void (*destroy_fn)(void *p_data))
 {
        struct vfs_fsp_data *ext;
        void * ext_data;
@@ -239,6 +252,7 @@ void *vfs_add_fsp_extension_notype(vfs_handle_struct *handle, files_struct *fsp,
 
        ext->owner = handle;
        ext->next = fsp->vfs_extension;
+       ext->destroy = destroy_fn;
        fsp->vfs_extension = ext;
        return EXT_DATA_AREA(ext);
 }
@@ -257,6 +271,9 @@ void vfs_remove_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
                    } else {
                            fsp->vfs_extension = curr->next;
                    }
+                   if (curr->destroy) {
+                           curr->destroy(EXT_DATA_AREA(curr));
+                   }
                    TALLOC_FREE(curr);
                    return;
                }
@@ -336,7 +353,7 @@ bool vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_
        if (SMB_VFS_STAT(conn,dname,st) != 0)
                return(False);
 
-       ret = S_ISDIR(st->st_mode);
+       ret = S_ISDIR(st->st_ex_mode);
        if(!ret)
                errno = ENOTDIR;
 
@@ -376,7 +393,7 @@ bool vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *
 
        if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
                return False;
-       return(S_ISREG(sbuf->st_mode));
+       return(S_ISREG(sbuf->st_ex_mode));
 }
 
 /****************************************************************************
@@ -509,8 +526,6 @@ int vfs_allocate_file_space(files_struct *fsp, uint64_t len)
        uint64_t space_avail;
        uint64_t bsize,dfree,dsize;
 
-       release_level_2_oplocks_on_change(fsp);
-
        /*
         * Actually try and commit the space on disk....
         */
@@ -527,28 +542,36 @@ int vfs_allocate_file_space(files_struct *fsp, uint64_t len)
        if (ret == -1)
                return ret;
 
-       if (len == (uint64_t)st.st_size)
+       if (len == (uint64_t)st.st_ex_size)
                return 0;
 
-       if (len < (uint64_t)st.st_size) {
+       if (len < (uint64_t)st.st_ex_size) {
                /* Shrink - use ftruncate. */
 
                DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
-                               fsp->fsp_name, (double)st.st_size ));
+                               fsp->fsp_name, (double)st.st_ex_size ));
+
+               contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_ALLOC_SHRINK);
 
                flush_write_cache(fsp, SIZECHANGE_FLUSH);
                if ((ret = SMB_VFS_FTRUNCATE(fsp, (SMB_OFF_T)len)) != -1) {
                        set_filelen_write_cache(fsp, len);
                }
+
+               contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_ALLOC_SHRINK);
+
                return ret;
        }
 
        /* Grow - we need to test if we have enough space. */
 
+       contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_ALLOC_GROW);
+       contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_ALLOC_GROW);
+
        if (!lp_strict_allocate(SNUM(fsp->conn)))
                return 0;
 
-       len -= st.st_size;
+       len -= st.st_ex_size;
        len /= 1024; /* Len is now number of 1k blocks needed. */
        space_avail = get_dfree_info(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
        if (space_avail == (uint64_t)-1) {
@@ -556,7 +579,7 @@ int vfs_allocate_file_space(files_struct *fsp, uint64_t len)
        }
 
        DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
-                       fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
+                       fsp->fsp_name, (double)st.st_ex_size, (double)len, (double)space_avail ));
 
        if (len > space_avail) {
                errno = ENOSPC;
@@ -576,7 +599,8 @@ int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
 {
        int ret;
 
-       release_level_2_oplocks_on_change(fsp);
+       contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_SET_FILE_LEN);
+
        DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
        flush_write_cache(fsp, SIZECHANGE_FLUSH);
        if ((ret = SMB_VFS_FTRUNCATE(fsp, len)) != -1) {
@@ -587,6 +611,8 @@ int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
                             fsp->fsp_name);
        }
 
+       contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_SET_FILE_LEN);
+
        return ret;
 }
 
@@ -597,7 +623,6 @@ int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
  Returns 0 on success, -1 on failure.
 ****************************************************************************/
 
-static char *sparse_buf;
 #define SPARSE_BUF_WRITE_SIZE (32*1024)
 
 int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
@@ -609,18 +634,19 @@ int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
        size_t num_to_write;
        ssize_t pwrite_ret;
 
-       release_level_2_oplocks_on_change(fsp);
        ret = SMB_VFS_FSTAT(fsp, &st);
        if (ret == -1) {
                return ret;
        }
 
-       if (len <= st.st_size) {
+       if (len <= st.st_ex_size) {
                return 0;
        }
 
        DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to len %.0f (%.0f bytes)\n",
-               fsp->fsp_name, (double)st.st_size, (double)len, (double)(len - st.st_size)));
+               fsp->fsp_name, (double)st.st_ex_size, (double)len, (double)(len - st.st_ex_size)));
+
+       contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_FILL_SPARSE);
 
        flush_write_cache(fsp, SIZECHANGE_FLUSH);
 
@@ -628,12 +654,13 @@ int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
                sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE);
                if (!sparse_buf) {
                        errno = ENOMEM;
-                       return -1;
+                       ret = -1;
+                       goto out;
                }
        }
 
-       offset = st.st_size;
-       num_to_write = len - st.st_size;
+       offset = st.st_ex_size;
+       num_to_write = len - st.st_ex_size;
        total = 0;
 
        while (total < num_to_write) {
@@ -643,17 +670,23 @@ int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
                if (pwrite_ret == -1) {
                        DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s\n",
                                fsp->fsp_name, strerror(errno) ));
-                       return -1;
+                       ret = -1;
+                       goto out;
                }
                if (pwrite_ret == 0) {
-                       return 0;
+                       ret = 0;
+                       goto out;
                }
 
                total += pwrite_ret;
        }
 
        set_filelen_write_cache(fsp, len);
-       return 0;
+
+       ret = 0;
+ out:
+       contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_FILL_SPARSE);
+       return ret;
 }
 
 /****************************************************************************
@@ -684,7 +717,7 @@ SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
  A vfs_readdir wrapper which just returns the file name.
 ********************************************************************/
 
-char *vfs_readdirname(connection_struct *conn, void *p)
+char *vfs_readdirname(connection_struct *conn, void *p, SMB_STRUCT_STAT *sbuf)
 {
        SMB_STRUCT_DIRENT *ptr= NULL;
        char *dname;
@@ -692,7 +725,7 @@ char *vfs_readdirname(connection_struct *conn, void *p)
        if (!p)
                return(NULL);
 
-       ptr = SMB_VFS_READDIR(conn, (DIR *)p);
+       ptr = SMB_VFS_READDIR(conn, (DIR *)p, sbuf);
        if (!ptr)
                return(NULL);
 
@@ -718,7 +751,6 @@ char *vfs_readdirname(connection_struct *conn, void *p)
 int vfs_ChDir(connection_struct *conn, const char *path)
 {
        int res;
-       static char *LastDir = NULL;
 
        if (!LastDir) {
                LastDir = SMB_STRDUP("");
@@ -746,18 +778,13 @@ int vfs_ChDir(connection_struct *conn, const char *path)
  format. Note this can be called with conn == NULL.
 ********************************************************************/
 
-struct getwd_cache_key {
-       SMB_DEV_T dev;
-       SMB_INO_T ino;
-};
-
 char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn)
 {
         char s[PATH_MAX+1];
        SMB_STRUCT_STAT st, st2;
        char *result;
        DATA_BLOB cache_value;
-       struct getwd_cache_key key;
+       struct file_id key;
 
        *s = 0;
 
@@ -777,9 +804,7 @@ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn)
                goto nocache;
        }
 
-       ZERO_STRUCT(key); /* unlikely, but possible padding */
-       key.dev = st.st_dev;
-       key.ino = st.st_ino;
+       key = vfs_file_id_from_sbuf(conn, &st);
 
        if (!memcache_lookup(smbd_memcache(), GETWD_CACHE,
                             data_blob_const(&key, sizeof(key)),
@@ -791,8 +816,8 @@ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn)
                   && (cache_value.data[cache_value.length-1] == '\0'));
 
        if ((SMB_VFS_STAT(conn, (char *)cache_value.data, &st2) == 0)
-           && (st.st_dev == st2.st_dev) && (st.st_ino == st2.st_ino)
-           && (S_ISDIR(st.st_mode))) {
+           && (st.st_ex_dev == st2.st_ex_dev) && (st.st_ex_ino == st2.st_ex_ino)
+           && (S_ISDIR(st.st_ex_mode))) {
                /*
                 * Ok, we're done
                 */
@@ -818,9 +843,7 @@ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn)
        }
 
        if (lp_getwd_cache() && VALID_STAT(st)) {
-               ZERO_STRUCT(key); /* unlikely, but possible padding */
-               key.dev = st.st_dev;
-               key.ino = st.st_ino;
+               key = vfs_file_id_from_sbuf(conn, &st);
 
                memcache_add(smbd_memcache(), GETWD_CACHE,
                             data_blob_const(&key, sizeof(key)),
@@ -848,7 +871,6 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname)
        bool free_resolved_name = False;
 #endif
        char *resolved_name = NULL;
-       size_t con_path_len = strlen(conn->connectpath);
        char *p = NULL;
 
        DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
@@ -934,12 +956,28 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname)
        }
 
        /* Check for widelinks allowed. */
-       if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) {
-               DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
-               if (free_resolved_name) {
-                       SAFE_FREE(resolved_name);
-               }
-               return NT_STATUS_ACCESS_DENIED;
+       if (!lp_widelinks(SNUM(conn))) {
+                   const char *conn_rootdir;
+
+                   conn_rootdir = SMB_VFS_CONNECTPATH(conn, fname);
+                   if (conn_rootdir == NULL) {
+                           DEBUG(2, ("check_reduced_name: Could not get conn_rootdir\n"));
+                           if (free_resolved_name) {
+                                   SAFE_FREE(resolved_name);
+                           }
+                           return NT_STATUS_ACCESS_DENIED;
+                   }
+
+                   if (strncmp(conn_rootdir, resolved_name,
+                               strlen(conn_rootdir)) != 0) {
+                           DEBUG(2, ("reduce_name: Bad access attempt: %s is "
+                                     "a symlink outside the share path",
+                                     fname));
+                           if (free_resolved_name) {
+                                   SAFE_FREE(resolved_name);
+                           }
+                           return NT_STATUS_ACCESS_DENIED;
+                   }
        }
 
         /* Check if we are allowing users to follow symlinks */
@@ -950,7 +988,7 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname)
         if (!lp_symlinks(SNUM(conn))) {
                 SMB_STRUCT_STAT statbuf;
                 if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
-                                (S_ISLNK(statbuf.st_mode)) ) {
+                                (S_ISLNK(statbuf.st_ex_mode)) ) {
                        if (free_resolved_name) {
                                SAFE_FREE(resolved_name);
                        }