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.
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;
};
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 */
}
/*
- * We know we never get a path continaing
+ * We know we never get a path containing
* DOT or DOTDOT.
*/
config->cwd,
NULL,
NULL,
+ 0,
0);
}
resolved_pathname,
NULL,
NULL,
+ 0,
0);
TALLOC_FREE(pathname);
TALLOC_FREE(resolved_pathname);
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
.chdir_fn = widelinks_chdir,
.getwd_fn = widelinks_getwd,
.realpath_fn = widelinks_realpath,
- .readdir_fn = widelinks_readdir
};
static_decl_vfs;