if (req->posix_pathnames) {
ucf_flags |= UCF_POSIX_PATHNAMES;
- if (!req->sconn->using_smb2) {
+ if (!conn_using_smb2(req->sconn)) {
ucf_flags |= UCF_LCOMP_LNK_OK;
}
}
return ret;
}
-static NTSTATUS safe_symlink_target_path(
- TALLOC_CTX *mem_ctx,
- const char *connectpath,
- const char *name_in,
- const char *substitute,
- size_t unparsed,
- char **_name_out)
+NTSTATUS safe_symlink_target_path(TALLOC_CTX *mem_ctx,
+ const char *connectpath,
+ const char *dir,
+ const char *target,
+ size_t unparsed,
+ char **_relative)
{
- char *target = NULL;
char *abs_target = NULL;
char *abs_target_canon = NULL;
const char *relative = NULL;
- char *name_out = NULL;
- NTSTATUS status = NT_STATUS_NO_MEMORY;
bool in_share;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
- target = symlink_target_path(mem_ctx, name_in, substitute, unparsed);
- if (target == NULL) {
- goto fail;
- }
-
- DBG_DEBUG("name_in: %s, substitute: %s, unparsed: %zu, target=%s\n",
- name_in,
- substitute,
- unparsed,
- target);
+ DBG_DEBUG("connectpath [%s] target [%s] unparsed [%zu]\n",
+ connectpath, target, unparsed);
if (target[0] == '/') {
- abs_target = target;
+ abs_target = talloc_strdup(mem_ctx, target);
+ } else if (dir == NULL) {
+ abs_target = talloc_asprintf(mem_ctx,
+ "%s/%s",
+ connectpath,
+ target);
+ } else if (dir[0] == '/') {
+ abs_target = talloc_asprintf(mem_ctx,
+ "%s/%s",
+ dir,
+ target);
} else {
- abs_target = talloc_asprintf(
- target, "%s/%s", connectpath, target);
- if (abs_target == NULL) {
- goto fail;
- }
+ abs_target = talloc_asprintf(mem_ctx,
+ "%s/%s/%s",
+ connectpath,
+ dir,
+ target);
+ }
+ if (abs_target == NULL) {
+ goto fail;
}
- abs_target_canon = canonicalize_absolute_path(target, abs_target);
+ abs_target_canon = canonicalize_absolute_path(abs_target, abs_target);
if (abs_target_canon == NULL) {
goto fail;
}
goto fail;
}
- name_out = talloc_strdup(mem_ctx, relative);
- if (name_out == NULL) {
+ *_relative = talloc_strdup(mem_ctx, relative);
+ if (*_relative == NULL) {
goto fail;
}
status = NT_STATUS_OK;
- *_name_out = name_out;
fail:
- TALLOC_FREE(target);
+ TALLOC_FREE(abs_target);
return status;
}
NTTIME twrp,
struct files_struct **_dirfsp,
struct smb_filename **_smb_fname,
- struct open_symlink_err **_symlink_err)
+ struct reparse_data_buffer **_symlink_err)
{
struct smb_filename *smb_dirname = NULL;
struct smb_filename *smb_fname_rel = NULL;
struct smb_filename *smb_fname = NULL;
- struct open_symlink_err *symlink_err = NULL;
+ struct reparse_data_buffer *symlink_err = NULL;
const bool posix = (ucf_flags & UCF_POSIX_PATHNAMES);
char *dirname = NULL;
const char *fname_rel = NULL;
&symlink_err);
if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
+ struct symlink_reparse_struct
+ *lnk = &symlink_err->parsed.lnk;
+ size_t unparsed = lnk->unparsed_path_length;
size_t name_in_len, dirname_len;
name_in_len = strlen(name_in);
SMB_ASSERT(name_in_len >= dirname_len);
- symlink_err->unparsed += (name_in_len - dirname_len);
+ unparsed += (name_in_len - dirname_len);
+
+ if (unparsed > UINT16_MAX) {
+ status = NT_STATUS_BUFFER_OVERFLOW;
+ goto fail;
+ }
+
+ lnk->unparsed_path_length = unparsed;
*_symlink_err = symlink_err;
goto fail;
* Upper layers might need the link target. Here we
* still have the relname around, get the symlink err.
*/
- status = create_open_symlink_err(mem_ctx,
- smb_dirname->fsp,
- smb_fname_rel,
- &symlink_err);
+ status = read_symlink_reparse(mem_ctx,
+ smb_dirname->fsp,
+ smb_fname_rel,
+ &symlink_err);
if (!NT_STATUS_IS_OK(status)) {
DBG_DEBUG("Could not read symlink for %s: %s\n",
smb_fname_str_dbg(
struct files_struct **_dirfsp,
struct smb_filename **_smb_fname)
{
- struct open_symlink_err *symlink_err = NULL;
+ struct reparse_data_buffer *symlink_err = NULL;
+ struct symlink_reparse_struct *lnk = NULL;
NTSTATUS status;
- char *substitute = NULL;
char *target = NULL;
+ char *safe_target = NULL;
size_t symlink_redirects = 0;
next:
if (!NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
return status;
}
+ lnk = &symlink_err->parsed.lnk;
/*
* If we're on an MSDFS share, see if this is
* an MSDFS link.
*/
if (lp_host_msdfs() && lp_msdfs_root(SNUM(conn)) &&
- strnequal(symlink_err->reparse->substitute_name, "msdfs:", 6))
+ strnequal(lnk->substitute_name, "msdfs:", 6))
{
TALLOC_FREE(*_smb_fname);
TALLOC_FREE(symlink_err);
}
if (!lp_follow_symlinks(SNUM(conn))) {
- status = (symlink_err->unparsed == 0)
+ status = (lnk->unparsed_path_length == 0)
? NT_STATUS_OBJECT_NAME_NOT_FOUND
: NT_STATUS_OBJECT_PATH_NOT_FOUND;
TALLOC_FREE(symlink_err);
* resolve all symlinks locally.
*/
- substitute = symlink_err->reparse->substitute_name;
+ target = symlink_target_path(mem_ctx,
+ name_in,
+ lnk->substitute_name,
+ lnk->unparsed_path_length);
+ if (target == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
status = safe_symlink_target_path(mem_ctx,
conn->connectpath,
- name_in,
- substitute,
- symlink_err->unparsed,
- &target);
+ NULL,
+ target,
+ lnk->unparsed_path_length,
+ &safe_target);
TALLOC_FREE(symlink_err);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
- name_in = target;
+ name_in = safe_target;
symlink_redirects += 1;