s3:utils: let smbstatus report anonymous signing/encryption explicitly
[samba.git] / source3 / modules / vfs_widelinks.c
index 36bd3ec6377a58567870b949b183ada8125f7a5b..c5b5084e108eb38b3b7c5cf15a0e58f623dfa536 100644 (file)
@@ -34,7 +34,7 @@
  1). When the upper layer code does a chdir() call to a pathname,
  this module stores the requested pathname inside config->cwd.
 
- When the upper layer code does a getwd() or reapath(), we return
+ When the upper layer code does a getwd() or realpath(), we return
  the absolute path of the value stored in config->cwd, *not* the
  position on the underlying filesystem.
 
@@ -83,7 +83,7 @@
 
  idiom in the vfs functions.
 
- 2). The module hides the existance of symlinks by inside
+ 2). The module hides the existence of symlinks by inside
  lstat(), open(), and readdir() so long as it's not a POSIX
  pathname request (those requests *must* be aware of symlinks
  and the POSIX client has to follow them, it's expected that
 
 struct widelinks_config {
        bool active;
+       bool is_dfs_share;
        char *cwd;
 };
 
@@ -134,7 +135,8 @@ static int widelinks_connect(struct vfs_handle_struct *handle,
                DBG_ERR("vfs_widelinks module loaded with "
                        "widelinks = no\n");
        }
-
+       config->is_dfs_share =
+               (lp_host_msdfs() && lp_msdfs_root(SNUM(handle->conn)));
         SMB_VFS_HANDLE_SET_DATA(handle,
                                config,
                                NULL, /* free_fn */
@@ -161,7 +163,7 @@ static int widelinks_chdir(struct vfs_handle_struct *handle,
        }
 
        /*
-        * We know we never get a path continaing
+        * We know we never get a path containing
         * DOT or DOTDOT.
         */
 
@@ -238,6 +240,7 @@ static struct smb_filename *widelinks_getwd(vfs_handle_struct *handle,
                                config->cwd,
                                NULL,
                                NULL,
+                               0,
                                0);
 }
 
@@ -298,6 +301,7 @@ static struct smb_filename *widelinks_realpath(vfs_handle_struct *handle,
                                resolved_pathname,
                                NULL,
                                NULL,
+                               0,
                                0);
        TALLOC_FREE(pathname);
        TALLOC_FREE(resolved_pathname);
@@ -336,93 +340,64 @@ static int widelinks_lstat(vfs_handle_struct *handle,
        return SMB_VFS_NEXT_STAT(handle, smb_fname);
 }
 
-static int widelinks_open(vfs_handle_struct *handle,
-                       struct smb_filename *smb_fname,
-                       files_struct *fsp,
-                       int flags,
-                       mode_t mode)
+static int widelinks_openat(vfs_handle_struct *handle,
+                           const struct files_struct *dirfsp,
+                           const struct smb_filename *smb_fname,
+                           files_struct *fsp,
+                           const struct vfs_open_how *_how)
 {
+       struct vfs_open_how how = *_how;
        struct widelinks_config *config = NULL;
-
+       int ret;
        SMB_VFS_HANDLE_GET_DATA(handle,
                                config,
                                struct widelinks_config,
                                return -1);
 
-       if (!config->active) {
-               /* Module not active. */
-               return SMB_VFS_NEXT_OPEN(handle,
-                               smb_fname,
-                               fsp,
-                               flags,
-                               mode);
-       }
-
-       if (config->cwd == NULL) {
-               /* open before chdir. See note 1b above. */
-               return SMB_VFS_NEXT_OPEN(handle,
-                               smb_fname,
-                               fsp,
-                               flags,
-                               mode);
-       }
-
-       if (smb_fname->flags & SMB_FILENAME_POSIX_PATH) {
-               /* POSIX sees symlinks. */
-               return SMB_VFS_NEXT_OPEN(handle,
-                               smb_fname,
-                               fsp,
-                               flags,
-                               mode);
-       }
-
-       /* Remove O_NOFOLLOW. */
-       flags = (flags & ~O_NOFOLLOW);
-
-       return SMB_VFS_NEXT_OPEN(handle,
-                       smb_fname,
-                       fsp,
-                       flags,
-                       mode);
-}
-
-static struct dirent *widelinks_readdir(vfs_handle_struct *handle,
-                       DIR *dirp,
-                       SMB_STRUCT_STAT *sbuf)
-{
-       struct widelinks_config *config = NULL;
-       struct dirent *result;
-
-       SMB_VFS_HANDLE_GET_DATA(handle,
-                               config,
-                               struct widelinks_config,
-                               return NULL);
-
-       result = SMB_VFS_NEXT_READDIR(handle,
-                               dirp,
-                               sbuf);
-
-       if (!config->active) {
-               /* Module not active. */
-               return result;
+       if (config->active &&
+           (config->cwd != NULL) &&
+           !(smb_fname->flags & SMB_FILENAME_POSIX_PATH))
+       {
+               /*
+                * Module active, openat after chdir (see note 1b above) and not
+                * a POSIX open (POSIX sees symlinks), so remove O_NOFOLLOW.
+                */
+               how.flags = (how.flags & ~O_NOFOLLOW);
        }
 
-       /*
-        * Prevent optimization of returning
-        * the stat info. Force caller to go
-        * through our LSTAT that hides symlinks.
-        */
-
-       if (sbuf) {
-               SET_STAT_INVALID(*sbuf);
+       ret = SMB_VFS_NEXT_OPENAT(handle,
+                                  dirfsp,
+                                  smb_fname,
+                                  fsp,
+                                  &how);
+       if (config->is_dfs_share && ret == -1 && errno == ENOENT) {
+               struct smb_filename *full_fname = NULL;
+               int lstat_ret;
+
+               full_fname = full_path_from_dirfsp_atname(talloc_tos(),
+                               dirfsp,
+                               smb_fname);
+               if (full_fname == NULL) {
+                       errno = ENOMEM;
+                       return -1;
+               }
+               lstat_ret = SMB_VFS_NEXT_LSTAT(handle,
+                               full_fname);
+               if (lstat_ret != -1 &&
+                   VALID_STAT(full_fname->st) &&
+                   S_ISLNK(full_fname->st.st_ex_mode)) {
+                       fsp->fsp_name->st = full_fname->st;
+               }
+               TALLOC_FREE(full_fname);
+               errno = ELOOP;
        }
-       return result;
+       return ret;
 }
 
 static struct vfs_fn_pointers vfs_widelinks_fns = {
        .connect_fn = widelinks_connect,
 
-       .open_fn = widelinks_open,
+       .openat_fn = widelinks_openat,
        .lstat_fn = widelinks_lstat,
        /*
         * NB. We don't need an lchown function as this
@@ -432,7 +407,6 @@ static struct vfs_fn_pointers vfs_widelinks_fns = {
        .chdir_fn = widelinks_chdir,
        .getwd_fn = widelinks_getwd,
        .realpath_fn = widelinks_realpath,
-       .readdir_fn = widelinks_readdir
 };
 
 static_decl_vfs;