connection_struct *conn;
DIR *dir;
long offset;
- char *dir_path;
+ struct smb_filename *dir_smb_fname;
size_t name_cache_size;
struct name_cache_entry *name_cache;
unsigned int name_cache_index;
bool expect_close;
char *wcard;
uint32_t attr;
- char *path;
+ struct smb_filename *smb_dname;
bool has_wild; /* Set to true if the wcard entry has MS wildcard characters in it. */
bool did_stat; /* Optimisation for non-wcard searches. */
bool priv; /* Directory handle opened with privilege. */
if (sconn->searches.dirhandles_open >= MAX_OPEN_DIRECTORIES)
dptr_idleoldest(sconn);
DEBUG(4,("dptr_get: Reopening dptr key %d\n",key));
- if (!(dptr->dir_hnd = OpenDir(
- NULL, dptr->conn, dptr->path,
- dptr->wcard, dptr->attr))) {
- DEBUG(4,("dptr_get: Failed to open %s (%s)\n",dptr->path,
+
+ if (!(dptr->dir_hnd = OpenDir(NULL,
+ dptr->conn,
+ dptr->smb_dname,
+ dptr->wcard,
+ dptr->attr))) {
+ DEBUG(4,("dptr_get: Failed to "
+ "open %s (%s)\n",
+ dptr->smb_dname->base_name,
strerror(errno)));
return NULL;
}
{
struct dptr_struct *dptr = dptr_get(sconn, key, false);
if (dptr)
- return(dptr->path);
+ return(dptr->smb_dname->base_name);
return(NULL);
}
struct dptr_struct *dptr, *next;
for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
next = dptr->next;
- if (spid == dptr->spid && strequal(dptr->path,path))
+ if (spid == dptr->spid &&
+ strequal(dptr->smb_dname->base_name,path)) {
dptr_close_internal(dptr);
+ }
}
}
static struct smb_Dir *open_dir_with_privilege(connection_struct *conn,
struct smb_request *req,
- const char *path,
+ const struct smb_filename *smb_dname,
const char *wcard,
uint32_t attr)
{
struct smb_Dir *dir_hnd = NULL;
- struct smb_filename *smb_fname_cwd;
- char *saved_dir = vfs_GetWd(talloc_tos(), conn);
+ struct smb_filename *smb_fname_cwd = NULL;
+ struct smb_filename *saved_dir_fname = vfs_GetWd(talloc_tos(), conn);
struct privilege_paths *priv_paths = req->priv_paths;
int ret;
- if (saved_dir == NULL) {
+ if (saved_dir_fname == NULL) {
return NULL;
}
- if (vfs_ChDir(conn, path) == -1) {
+ if (vfs_ChDir(conn, smb_dname) == -1) {
return NULL;
}
/* Now check the stat value is the same. */
- smb_fname_cwd = synthetic_smb_fname(talloc_tos(), ".", NULL, NULL);
-
+ smb_fname_cwd = synthetic_smb_fname(talloc_tos(),
+ ".",
+ NULL,
+ NULL,
+ smb_dname->flags);
if (smb_fname_cwd == NULL) {
goto out;
}
if (!check_same_stat(&smb_fname_cwd->st, &priv_paths->parent_name.st)) {
DEBUG(0,("open_dir_with_privilege: stat mismatch between %s "
"and %s\n",
- path,
+ smb_dname->base_name,
smb_fname_str_dbg(&priv_paths->parent_name)));
goto out;
}
- dir_hnd = OpenDir(NULL, conn, ".", wcard, attr);
+ dir_hnd = OpenDir(NULL, conn, smb_fname_cwd, wcard, attr);
out:
- vfs_ChDir(conn, saved_dir);
+ vfs_ChDir(conn, saved_dir_fname);
+ TALLOC_FREE(saved_dir_fname);
return dir_hnd;
}
NTSTATUS dptr_create(connection_struct *conn,
struct smb_request *req,
files_struct *fsp,
- const char *path, bool old_handle, bool expect_close,uint16_t spid,
- const char *wcard, bool wcard_has_wild, uint32_t attr, struct dptr_struct **dptr_ret)
+ const struct smb_filename *smb_dname,
+ bool old_handle,
+ bool expect_close,
+ uint16_t spid,
+ const char *wcard,
+ bool wcard_has_wild,
+ uint32_t attr,
+ struct dptr_struct **dptr_ret)
{
struct smbd_server_connection *sconn = conn->sconn;
struct dptr_struct *dptr = NULL;
struct smb_Dir *dir_hnd;
if (fsp && fsp->is_directory && fsp->fh->fd != -1) {
- path = fsp->fsp_name->base_name;
+ smb_dname = fsp->fsp_name;
}
- DEBUG(5,("dptr_create dir=%s\n", path));
+ DEBUG(5,("dptr_create dir=%s\n", smb_dname->base_name));
if (sconn == NULL) {
DEBUG(0,("dptr_create: called with fake connection_struct\n"));
if (!(fsp->access_mask & SEC_DIR_LIST)) {
DEBUG(5,("dptr_create: directory %s "
"not open for LIST access\n",
- path));
+ smb_dname->base_name));
return NT_STATUS_ACCESS_DENIED;
}
dir_hnd = OpenDir_fsp(NULL, conn, fsp, wcard, attr);
} else {
int ret;
bool backup_intent = (req && req->priv_paths);
- struct smb_filename *smb_dname;
NTSTATUS status;
+ struct smb_filename *smb_dname_cp =
+ cp_smb_filename(talloc_tos(), smb_dname);
- smb_dname = synthetic_smb_fname(talloc_tos(), path,
- NULL, NULL);
- if (smb_dname == NULL) {
+ if (smb_dname_cp == NULL) {
return NT_STATUS_NO_MEMORY;
}
- if (lp_posix_pathnames()) {
- ret = SMB_VFS_LSTAT(conn, smb_dname);
+
+ if (req != NULL && req->posix_pathnames) {
+ ret = SMB_VFS_LSTAT(conn, smb_dname_cp);
} else {
- ret = SMB_VFS_STAT(conn, smb_dname);
+ ret = SMB_VFS_STAT(conn, smb_dname_cp);
}
if (ret == -1) {
- return map_nt_error_from_unix(errno);
+ status = map_nt_error_from_unix(errno);
+ TALLOC_FREE(smb_dname_cp);
+ return status;
}
- if (!S_ISDIR(smb_dname->st.st_ex_mode)) {
+ if (!S_ISDIR(smb_dname_cp->st.st_ex_mode)) {
+ TALLOC_FREE(smb_dname_cp);
return NT_STATUS_NOT_A_DIRECTORY;
}
status = smbd_check_access_rights(conn,
- smb_dname,
+ smb_dname_cp,
backup_intent,
SEC_DIR_LIST);
if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(smb_dname_cp);
return status;
}
if (backup_intent) {
dir_hnd = open_dir_with_privilege(conn,
req,
- path,
+ smb_dname_cp,
wcard,
attr);
} else {
- dir_hnd = OpenDir(NULL, conn, path, wcard, attr);
+ dir_hnd = OpenDir(NULL,
+ conn,
+ smb_dname_cp,
+ wcard,
+ attr);
}
+ TALLOC_FREE(smb_dname_cp);
}
if (!dir_hnd) {
return NT_STATUS_NO_MEMORY;
}
- dptr->path = talloc_strdup(dptr, path);
- if (!dptr->path) {
+ dptr->smb_dname = cp_smb_filename(dptr, smb_dname);
+ if (!dptr->smb_dname) {
TALLOC_FREE(dptr);
TALLOC_FREE(dir_hnd);
return NT_STATUS_NO_MEMORY;
TALLOC_FREE(dir_hnd);
return NT_STATUS_NO_MEMORY;
}
- if (lp_posix_pathnames() || (wcard[0] == '.' && wcard[1] == 0)) {
+ if ((req != NULL && req->posix_pathnames) ||
+ (wcard[0] == '.' && wcard[1] == 0)) {
dptr->has_wild = True;
} else {
dptr->has_wild = wcard_has_wild;
done:
DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
- dptr->dnum,path,expect_close));
+ dptr->dnum,
+ dptr->smb_dname->base_name,
+ expect_close));
*dptr_ret = dptr;
while ((name = ReadDirName(dptr->dir_hnd, poffset, pst, &talloced))
!= NULL) {
- if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
+ if (is_visible_file(dptr->conn,
+ dptr->smb_dname->base_name,
+ name,
+ pst,
+ true)) {
*ptalloced = talloced;
return name;
}
dptr->did_stat = true;
/* First check if it should be visible. */
- if (!is_visible_file(dptr->conn, dptr->path, dptr->wcard,
- pst, true))
- {
+ if (!is_visible_file(dptr->conn,
+ dptr->smb_dname->base_name,
+ dptr->wcard,
+ pst,
+ true)) {
/* This only returns false if the file was found, but
is explicitly not visible. Set us to end of
directory, but return NULL as we know we can't ever
pathreal = talloc_asprintf(ctx,
"%s/%s",
- dptr->path,
+ dptr->smb_dname->base_name,
dptr->wcard);
if (!pathreal)
return NULL;
* Try case-insensitive stat if the fs has the ability. This avoids
* scanning the whole directory.
*/
- ret = SMB_VFS_GET_REAL_FILENAME(dptr->conn, dptr->path, dptr->wcard,
- ctx, &found_name);
+ ret = SMB_VFS_GET_REAL_FILENAME(dptr->conn,
+ dptr->smb_dname->base_name,
+ dptr->wcard,
+ ctx,
+ &found_name);
if (ret == 0) {
name = found_name;
goto clean;
seekoff = map_wire_to_dir_offset(dptr, wire_offset);
SeekDir(dptr->dir_hnd,seekoff);
DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
- key, dptr->path, (int)seekoff));
+ key, dptr->smb_dname->base_name, (int)seekoff));
return(dptr);
}
DEBUG(3,("fetched null dirptr %d\n",dptr_num));
return(NULL);
}
- DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr->path));
+ DEBUG(3,("fetching dirptr %d for path %s\n",
+ dptr_num,
+ dptr->smb_dname->base_name));
return(dptr);
}
connection_struct *conn = dirptr->conn;
size_t slashlen;
size_t pathlen;
- bool dirptr_path_is_dot = ISDOT(dirptr->path);
+ const char *dpath = dirptr->smb_dname->base_name;
+ bool dirptr_path_is_dot = ISDOT(dpath);
*_smb_fname = NULL;
*_mode = 0;
- pathlen = strlen(dirptr->path);
- slashlen = ( dirptr->path[pathlen-1] != '/') ? 1 : 0;
+ pathlen = strlen(dpath);
+ slashlen = ( dpath[pathlen-1] != '/') ? 1 : 0;
while (true) {
long cur_offset;
if (dirptr_path_is_dot) {
memcpy(pathreal, dname, talloc_get_size(dname));
} else {
- memcpy(pathreal, dirptr->path, pathlen);
+ memcpy(pathreal, dpath, pathlen);
pathreal[pathlen] = '/';
memcpy(pathreal + slashlen + pathlen, dname,
talloc_get_size(dname));
}
status = SMB_VFS_GET_NT_ACL(conn,
- smb_fname->base_name,
+ smb_fname,
(SECINFO_OWNER |
SECINFO_GROUP |
SECINFO_DACL),
}
/* Create an smb_filename with stream_name == NULL. */
- smb_fname_base = synthetic_smb_fname(talloc_tos(), entry, NULL,
- pst);
+ smb_fname_base = synthetic_smb_fname(talloc_tos(),
+ entry,
+ NULL,
+ pst,
+ 0);
if (smb_fname_base == NULL) {
ret = false;
goto out;
Open a directory.
********************************************************************/
-struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
- const char *name,
+static struct smb_Dir *OpenDir_internal(TALLOC_CTX *mem_ctx,
+ connection_struct *conn,
+ const struct smb_filename *smb_dname,
const char *mask,
uint32_t attr)
{
return NULL;
}
- dirp->conn = conn;
- dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
+ dirp->dir = SMB_VFS_OPENDIR(conn, smb_dname, mask, attr);
- dirp->dir_path = talloc_strdup(dirp, name);
- if (!dirp->dir_path) {
- errno = ENOMEM;
+ if (!dirp->dir) {
+ DEBUG(5,("OpenDir: Can't open %s. %s\n",
+ smb_dname->base_name,
+ strerror(errno) ));
goto fail;
}
+ dirp->conn = conn;
+ dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
+
if (sconn && !sconn->using_smb2) {
sconn->searches.dirhandles_open++;
}
talloc_set_destructor(dirp, smb_Dir_destructor);
- dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
- if (!dirp->dir) {
- DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path,
- strerror(errno) ));
- goto fail;
- }
-
return dirp;
fail:
return NULL;
}
+/****************************************************************************
+ Open a directory handle by pathname, ensuring it's under the share path.
+****************************************************************************/
+
+static struct smb_Dir *open_dir_safely(TALLOC_CTX *ctx,
+ connection_struct *conn,
+ const struct smb_filename *smb_dname,
+ const char *wcard,
+ uint32_t attr)
+{
+ struct smb_Dir *dir_hnd = NULL;
+ struct smb_filename *smb_fname_cwd = NULL;
+ struct smb_filename *saved_dir_fname = vfs_GetWd(ctx, conn);
+ NTSTATUS status;
+
+ if (saved_dir_fname == NULL) {
+ return NULL;
+ }
+
+ if (vfs_ChDir(conn, smb_dname) == -1) {
+ goto out;
+ }
+
+ smb_fname_cwd = synthetic_smb_fname(talloc_tos(),
+ ".",
+ NULL,
+ NULL,
+ smb_dname->flags);
+ if (smb_fname_cwd == NULL) {
+ goto out;
+ }
+
+ /*
+ * Now the directory is pinned, use
+ * REALPATH to ensure we can access it.
+ */
+ status = check_name(conn, smb_fname_cwd);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+
+ dir_hnd = OpenDir_internal(ctx,
+ conn,
+ smb_fname_cwd,
+ wcard,
+ attr);
+
+ if (dir_hnd == NULL) {
+ goto out;
+ }
+
+ /*
+ * OpenDir_internal only gets "." as the dir name.
+ * Store the real dir name here.
+ */
+
+ dir_hnd->dir_smb_fname = cp_smb_filename(dir_hnd, smb_dname);
+ if (!dir_hnd->dir_smb_fname) {
+ TALLOC_FREE(dir_hnd);
+ errno = ENOMEM;
+ }
+
+ out:
+
+ vfs_ChDir(conn, saved_dir_fname);
+ TALLOC_FREE(saved_dir_fname);
+ return dir_hnd;
+}
+
+struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
+ const struct smb_filename *smb_dname,
+ const char *mask,
+ uint32_t attr)
+{
+ return open_dir_safely(mem_ctx,
+ conn,
+ smb_dname,
+ mask,
+ attr);
+}
+
/*******************************************************************
Open a directory from an fsp.
********************************************************************/
struct smbd_server_connection *sconn = conn->sconn;
if (!dirp) {
- return NULL;
+ goto fail;
+ }
+
+ if (!fsp->is_directory) {
+ errno = EBADF;
+ goto fail;
+ }
+
+ if (fsp->fh->fd == -1) {
+ errno = EBADF;
+ goto fail;
}
dirp->conn = conn;
dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
- dirp->dir_path = talloc_strdup(dirp, fsp->fsp_name->base_name);
- if (!dirp->dir_path) {
+ dirp->dir_smb_fname = cp_smb_filename(dirp, fsp->fsp_name);
+ if (!dirp->dir_smb_fname) {
errno = ENOMEM;
goto fail;
}
- if (sconn && !sconn->using_smb2) {
- sconn->searches.dirhandles_open++;
- }
- talloc_set_destructor(dirp, smb_Dir_destructor);
-
- if (fsp->is_directory && fsp->fh->fd != -1) {
- dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
- if (dirp->dir != NULL) {
- dirp->fsp = fsp;
- } else {
- DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
- "NULL (%s)\n",
- dirp->dir_path,
- strerror(errno)));
- if (errno != ENOSYS) {
- return NULL;
- }
+ dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
+ if (dirp->dir != NULL) {
+ dirp->fsp = fsp;
+ } else {
+ DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
+ "NULL (%s)\n",
+ dirp->dir_smb_fname->base_name,
+ strerror(errno)));
+ if (errno != ENOSYS) {
+ goto fail;
}
}
if (dirp->dir == NULL) {
- /* FDOPENDIR didn't work. Use OPENDIR instead. */
- dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
+ /* FDOPENDIR is not supported. Use OPENDIR instead. */
+ TALLOC_FREE(dirp);
+ return open_dir_safely(mem_ctx,
+ conn,
+ fsp->fsp_name,
+ mask,
+ attr);
}
- if (!dirp->dir) {
- DEBUG(5,("OpenDir_fsp: Can't open %s. %s\n", dirp->dir_path,
- strerror(errno) ));
- goto fail;
+ if (sconn && !sconn->using_smb2) {
+ sconn->searches.dirhandles_open++;
}
+ talloc_set_destructor(dirp, smb_Dir_destructor);
return dirp;
return 0;
}
- if (memcmp(state->dirpath, fullpath, len) != 0) {
+ if (memcmp(state->dirpath, fullpath, state->dirpath_len) != 0) {
/*
* Not a parent
*/
return 0;
}
- return state->fn(fid, data, private_data);
+ return state->fn(fid, data, state->private_data);
}
static int files_below_forall(connection_struct *conn,
void *private_data),
void *private_data)
{
- struct files_below_forall_state state = {};
+ struct files_below_forall_state state = {
+ .fn = fn,
+ .private_data = private_data,
+ };
int ret;
char tmpbuf[PATH_MAX];
char *to_free;
return 1;
}
-static bool have_file_open_below(connection_struct *conn,
+bool have_file_open_below(connection_struct *conn,
const struct smb_filename *name)
{
- struct have_file_open_below_state state = {};
+ struct have_file_open_below_state state = {
+ .found_one = false,
+ };
int ret;
if (!VALID_STAT(name->st)) {
return status;
}
- if (!lp_posix_pathnames() &&
+ if (!(fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) &&
lp_strict_rename(SNUM(conn)) &&
have_file_open_below(fsp->conn, fsp->fsp_name))
{