mirror of
https://github.com/samba-team/samba.git
synced 2025-08-24 21:49:29 +03:00
smbd: Simplify smbd_dirptr_get_entry()
This uses the much simpler openat_pathef_fsp_lcomp, avoiding non_widelink_open where we don't need it. The only case where we still have to call openat_pathref_fsp() in its full capacity is to find out whether a symlink we found is dangling or not. Signed-off-by: Volker Lendecke <vl@samba.org> Reviewed-by: Jeremy Allison <jra@samba.org>
This commit is contained in:
@ -551,10 +551,10 @@ bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
|
||||
char *dname = NULL;
|
||||
char *fname = NULL;
|
||||
struct smb_filename *smb_fname = NULL;
|
||||
struct open_symlink_err *symlink_err = NULL;
|
||||
uint32_t mode = 0;
|
||||
bool get_dosmode = get_dosmode_in;
|
||||
bool toplevel_dotdot;
|
||||
bool visible;
|
||||
bool ok;
|
||||
|
||||
dname = dptr_ReadDirName(ctx, dirptr);
|
||||
@ -589,44 +589,48 @@ bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
|
||||
|
||||
toplevel_dotdot = toplevel && ISDOTDOT(dname);
|
||||
|
||||
if (ISDOT(dname) || ISDOTDOT(dname)) {
|
||||
smb_fname = synthetic_smb_fname(talloc_tos(),
|
||||
toplevel_dotdot ? "." : dname,
|
||||
NULL,
|
||||
NULL,
|
||||
dir_fname->twrp,
|
||||
dir_fname->flags);
|
||||
if (smb_fname == NULL) {
|
||||
TALLOC_FREE(dname);
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *dotname = dname;
|
||||
/*
|
||||
* UCF_POSIX_PATHNAMES to avoid the readdir fallback
|
||||
* if we get raced between readdir and unlink.
|
||||
*/
|
||||
status = openat_pathref_fsp_lcomp(dir_hnd->fsp,
|
||||
smb_fname,
|
||||
UCF_POSIX_PATHNAMES);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DBG_DEBUG("Could not open %s: %s\n",
|
||||
dname,
|
||||
nt_errstr(status));
|
||||
TALLOC_FREE(smb_fname);
|
||||
TALLOC_FREE(fname);
|
||||
TALLOC_FREE(dname);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (toplevel_dotdot) {
|
||||
/*
|
||||
* Handle ".." in toplevel like "." to not
|
||||
* leak info from outside the share.
|
||||
*/
|
||||
dotname = ".";
|
||||
visible = is_visible_fsp(smb_fname->fsp);
|
||||
if (!visible) {
|
||||
TALLOC_FREE(smb_fname);
|
||||
TALLOC_FREE(fname);
|
||||
TALLOC_FREE(dname);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!S_ISLNK(smb_fname->st.st_ex_mode)) {
|
||||
if (get_dosmode) {
|
||||
mode = fdos_mode(smb_fname->fsp);
|
||||
smb_fname->st = smb_fname->fsp->fsp_name->st;
|
||||
}
|
||||
|
||||
smb_fname = synthetic_smb_fname(talloc_tos(),
|
||||
dotname,
|
||||
NULL,
|
||||
NULL,
|
||||
dir_fname->twrp,
|
||||
dir_fname->flags);
|
||||
if (smb_fname == NULL) {
|
||||
TALLOC_FREE(dname);
|
||||
return false;
|
||||
}
|
||||
|
||||
status = openat_pathref_fsp(dir_hnd->fsp, smb_fname);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DBG_INFO("Could not open \"..\": %s\n",
|
||||
nt_errstr(status));
|
||||
TALLOC_FREE(smb_fname);
|
||||
TALLOC_FREE(dname);
|
||||
continue;
|
||||
}
|
||||
|
||||
mode = fdos_mode(smb_fname->fsp);
|
||||
|
||||
/*
|
||||
* Don't leak INO/DEV/User SID/Group SID about
|
||||
* the containing directory of the share.
|
||||
*/
|
||||
if (toplevel_dotdot) {
|
||||
/*
|
||||
* Ensure posix fileid and sids are hidden
|
||||
@ -640,123 +644,74 @@ bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = openat_pathref_fsp_nosymlink(talloc_tos(),
|
||||
conn,
|
||||
dir_hnd->fsp,
|
||||
dname,
|
||||
dir_fname->twrp,
|
||||
posix,
|
||||
&smb_fname,
|
||||
&symlink_err);
|
||||
if (lp_host_msdfs() && lp_msdfs_root(SNUM(conn)) &&
|
||||
is_msdfs_link(dir_hnd->fsp, smb_fname))
|
||||
{
|
||||
DBG_INFO("Masquerading msdfs link %s as a directory\n",
|
||||
smb_fname->base_name);
|
||||
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
bool visible = is_visible_fsp(smb_fname->fsp);
|
||||
if (!visible) {
|
||||
TALLOC_FREE(smb_fname);
|
||||
TALLOC_FREE(dname);
|
||||
TALLOC_FREE(fname);
|
||||
continue;
|
||||
}
|
||||
} else if (NT_STATUS_EQUAL(status,
|
||||
NT_STATUS_STOPPED_ON_SYMLINK)) {
|
||||
struct symlink_reparse_struct *reparse =
|
||||
symlink_err->reparse;
|
||||
const char *target = reparse->substitute_name;
|
||||
bool is_msdfs_link;
|
||||
smb_fname->st.st_ex_mode = (smb_fname->st.st_ex_mode &
|
||||
~S_IFMT) |
|
||||
S_IFDIR;
|
||||
|
||||
is_msdfs_link = lp_host_msdfs();
|
||||
is_msdfs_link &= lp_msdfs_root(SNUM(conn));
|
||||
is_msdfs_link &= (strncmp(target, "msdfs:", 6) == 0);
|
||||
mode = dos_mode_msdfs(conn, dname, &smb_fname->st);
|
||||
get_dosmode = false;
|
||||
ask_sharemode = false;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (is_msdfs_link) {
|
||||
char *path = NULL;
|
||||
if (posix) {
|
||||
/*
|
||||
* Posix always wants to see symlinks,
|
||||
* dangling or not. We've done the
|
||||
* openat_pathref_fsp() to fill in
|
||||
* smb_fname->fsp just in case it's not
|
||||
* dangling.
|
||||
*/
|
||||
mode = FILE_ATTRIBUTE_NORMAL;
|
||||
get_dosmode = false;
|
||||
ask_sharemode = false;
|
||||
goto done;
|
||||
}
|
||||
|
||||
path = full_path_from_dirfsp_at_basename(
|
||||
talloc_tos(),
|
||||
dir_hnd->fsp,
|
||||
dname);
|
||||
if (path == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
smb_fname =
|
||||
synthetic_smb_fname(talloc_tos(),
|
||||
path,
|
||||
NULL,
|
||||
&symlink_err->st,
|
||||
dir_fname->twrp,
|
||||
dir_fname->flags);
|
||||
TALLOC_FREE(path);
|
||||
if (smb_fname == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DBG_INFO("Masquerading msdfs link %s as a"
|
||||
"directory\n",
|
||||
smb_fname->base_name);
|
||||
|
||||
smb_fname->st.st_ex_mode =
|
||||
(smb_fname->st.st_ex_mode & ~S_IFMT) |
|
||||
S_IFDIR;
|
||||
|
||||
mode = dos_mode_msdfs(conn,
|
||||
dname,
|
||||
&smb_fname->st);
|
||||
get_dosmode = false;
|
||||
ask_sharemode = false;
|
||||
goto done;
|
||||
}
|
||||
|
||||
smb_fname = synthetic_smb_fname(talloc_tos(),
|
||||
dname,
|
||||
NULL,
|
||||
&symlink_err->st,
|
||||
dir_fname->twrp,
|
||||
dir_fname->flags);
|
||||
if (smb_fname == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
status = openat_pathref_fsp(dir_hnd->fsp, smb_fname);
|
||||
|
||||
if (posix) {
|
||||
/*
|
||||
* Posix always wants to see symlinks,
|
||||
* dangling or not. We've done the
|
||||
* openat_pathref_fsp() to fill in
|
||||
* smb_fname->fsp just in case it's
|
||||
* not dangling.
|
||||
*/
|
||||
mode = FILE_ATTRIBUTE_NORMAL;
|
||||
get_dosmode = false;
|
||||
ask_sharemode = false;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
/*
|
||||
* Dangling symlink. Hide.
|
||||
*/
|
||||
TALLOC_FREE(smb_fname);
|
||||
TALLOC_FREE(fname);
|
||||
TALLOC_FREE(dname);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
DBG_NOTICE("Could not open %s: %s\n",
|
||||
dname,
|
||||
nt_errstr(status));
|
||||
TALLOC_FREE(dname);
|
||||
TALLOC_FREE(fname);
|
||||
if (!lp_follow_symlinks(SNUM(conn))) {
|
||||
/*
|
||||
* Hide symlinks not followed
|
||||
*/
|
||||
TALLOC_FREE(smb_fname);
|
||||
TALLOC_FREE(fname);
|
||||
TALLOC_FREE(dname);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have to find out if it's a dangling
|
||||
* symlink. Use the fat logic behind
|
||||
* openat_pathref_fsp().
|
||||
*/
|
||||
|
||||
{
|
||||
struct files_struct *fsp = smb_fname->fsp;
|
||||
smb_fname_fsp_unlink(smb_fname);
|
||||
fd_close(fsp);
|
||||
file_free(NULL, fsp);
|
||||
}
|
||||
|
||||
status = openat_pathref_fsp(dir_hnd->fsp, smb_fname);
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
/*
|
||||
* Dangling symlink. Hide.
|
||||
*/
|
||||
TALLOC_FREE(smb_fname);
|
||||
TALLOC_FREE(fname);
|
||||
TALLOC_FREE(dname);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (get_dosmode) {
|
||||
mode = fdos_mode(smb_fname->fsp);
|
||||
if (smb_fname->fsp != NULL) {
|
||||
smb_fname->st = smb_fname->fsp->fsp_name->st;
|
||||
}
|
||||
smb_fname->st = smb_fname->fsp->fsp_name->st;
|
||||
}
|
||||
|
||||
done:
|
||||
|
Reference in New Issue
Block a user