#include "fake_file.h"
#include "smbd/smbd.h"
#include "smbd/globals.h"
-#include "lib/util/memcache.h"
+#include "libcli/smb/reparse.h"
+#include "source3/smbd/dir.h"
uint32_t ucf_flags_from_smb_request(struct smb_request *req)
{
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;
}
}
const char *dname = NULL;
char *talloced = NULL;
char *unmangled_name = NULL;
- long curpos;
NTSTATUS status;
/* If we have a case-sensitive filesystem, it doesn't do us any
}
/* now scan for matching names */
- curpos = 0;
- while ((dname = ReadDirName(cur_dir, &curpos, NULL, &talloced))) {
+ while ((dname = ReadDirName(cur_dir, &talloced))) {
/* Is it dot or dot dot. */
if (ISDOT(dname) || ISDOTDOT(dname)) {
return status;
}
-/*
- * Create the memcache-key for GETREALFILENAME_CACHE: This supplements
- * the stat cache for the last component to be looked up. Cache
- * contents is the correctly capitalized translation of the parameter
- * "name" as it exists on disk. This is indexed by inode of the dirfsp
- * and name, and contrary to stat_cahce_lookup() it does not
- * vfs_stat() the last component. This will be taken care of by an
- * attempt to do a openat_pathref_fsp().
- */
-static bool get_real_filename_cache_key(
- TALLOC_CTX *mem_ctx,
- struct files_struct *dirfsp,
- const char *name,
- DATA_BLOB *_key)
-{
- struct file_id fid = vfs_file_id_from_sbuf(
- dirfsp->conn, &dirfsp->fsp_name->st);
- char *upper = NULL;
- uint8_t *key = NULL;
- size_t namelen, keylen;
-
- upper = talloc_strdup_upper(mem_ctx, name);
- if (upper == NULL) {
- return false;
- }
- namelen = talloc_get_size(upper);
-
- keylen = namelen + sizeof(fid);
- if (keylen < sizeof(fid)) {
- TALLOC_FREE(upper);
- return false;
- }
-
- key = talloc_size(mem_ctx, keylen);
- if (key == NULL) {
- TALLOC_FREE(upper);
- return false;
- }
-
- memcpy(key, &fid, sizeof(fid));
- memcpy(key + sizeof(fid), upper, namelen);
- TALLOC_FREE(upper);
-
- *_key = (DATA_BLOB) { .data = key, .length = keylen, };
- return true;
-}
-
/*
* Lightweight function to just get last component
* for rename / enumerate directory calls.
return orig_lcomp;
}
-/*
- * Deal with the SMB1 semantics of sending a pathname with a
- * wildcard as the terminal component for a SMB1search or
- * trans2 findfirst.
- */
-
-NTSTATUS filename_convert_smb1_search_path(TALLOC_CTX *ctx,
- connection_struct *conn,
- char *name_in,
- uint32_t ucf_flags,
- struct files_struct **_dirfsp,
- struct smb_filename **_smb_fname_out,
- char **_mask_out)
-{
- NTSTATUS status;
- char *p = NULL;
- char *mask = NULL;
- struct smb_filename *smb_fname = NULL;
- NTTIME twrp = 0;
-
- *_smb_fname_out = NULL;
- *_dirfsp = NULL;
- *_mask_out = NULL;
-
- DBG_DEBUG("name_in: %s\n", name_in);
-
- if (ucf_flags & UCF_GMT_PATHNAME) {
- extract_snapshot_token(name_in, &twrp);
- ucf_flags &= ~UCF_GMT_PATHNAME;
- }
-
- /* Get the original lcomp. */
- mask = get_original_lcomp(ctx,
- conn,
- name_in,
- ucf_flags);
- if (mask == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
-
- if (mask[0] == '\0') {
- /* Windows and OS/2 systems treat search on the root as * */
- TALLOC_FREE(mask);
- mask = talloc_strdup(ctx, "*");
- if (mask == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
- }
-
- DBG_DEBUG("mask = %s\n", mask);
-
- /*
- * Remove the terminal component so
- * filename_convert_dirfsp never sees the mask.
- */
- p = strrchr_m(name_in,'/');
- if (p == NULL) {
- /* filename_convert_dirfsp handles a '\0' name. */
- name_in[0] = '\0';
- } else {
- *p = '\0';
- }
-
- DBG_DEBUG("For filename_convert_dirfsp: name_in = %s\n",
- name_in);
-
- /* Convert the parent directory path. */
- status = filename_convert_dirfsp(ctx,
- conn,
- name_in,
- ucf_flags,
- twrp,
- _dirfsp,
- &smb_fname);
-
- if (!NT_STATUS_IS_OK(status)) {
- DBG_DEBUG("filename_convert error for %s: %s\n",
- name_in,
- nt_errstr(status));
- }
-
- *_smb_fname_out = talloc_move(ctx, &smb_fname);
- *_mask_out = talloc_move(ctx, &mask);
-
- return status;
-}
-
/*
* Get the correct capitalized stream name hanging off
* base_fsp. Equivalent of get_real_filename(), but for streams.
}
/*
- * No slash, dir is emtpy
+ * No slash, dir is empty
*/
dirname = talloc_strdup(mem_ctx, "");
if (dirname == NULL) {
return NT_STATUS_OK;
}
-/*
- * Open smb_fname_rel->fsp as a pathref fsp with a case insensitive
- * fallback using GETREALFILENAME_CACHE and get_real_filename_at() if
- * the first attempt based on the filename sent by the client gives
- * ENOENT.
- */
-static NTSTATUS openat_pathref_fsp_case_insensitive(
- struct files_struct *dirfsp,
- struct smb_filename *smb_fname_rel,
- uint32_t ucf_flags)
+static const char *previous_slash(const char *name_in, const char *slash)
{
- const bool posix = (ucf_flags & UCF_POSIX_PATHNAMES);
- DATA_BLOB cache_key = { .data = NULL, };
- char *found_name = NULL;
- NTSTATUS status;
- bool ok;
-
- SET_STAT_INVALID(smb_fname_rel->st);
-
- /* Check veto files - only looks at last component. */
- if (IS_VETO_PATH(dirfsp->conn, smb_fname_rel->base_name)) {
- DBG_DEBUG("veto files rejecting last component %s\n",
- smb_fname_str_dbg(smb_fname_rel));
- return NT_STATUS_OBJECT_NAME_NOT_FOUND;
- }
-
- status = openat_pathref_fsp(dirfsp, smb_fname_rel);
-
- if (NT_STATUS_IS_OK(status)) {
- return NT_STATUS_OK;
- }
-
- if (VALID_STAT(smb_fname_rel->st)) {
- /*
- * We got an error although the object existed. Might
- * be a symlink we don't want.
- */
- return status;
- }
-
- if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
- /*
- * Only retry on ENOENT
- */
- return status;
- }
-
- if (posix || dirfsp->conn->case_sensitive) {
- /*
- * Only return case insensitive if required
- */
- return status;
- }
-
- if (lp_stat_cache()) {
- char *base_name = smb_fname_rel->base_name;
- DATA_BLOB value = { .data = NULL };
-
- ok = get_real_filename_cache_key(
- talloc_tos(), dirfsp, base_name, &cache_key);
- if (!ok) {
- /*
- * probably ENOMEM, just bail
- */
- return status;
- }
-
- DO_PROFILE_INC(statcache_lookups);
-
- ok = memcache_lookup(
- NULL, GETREALFILENAME_CACHE, cache_key, &value);
- if (!ok) {
- DO_PROFILE_INC(statcache_misses);
- goto lookup;
- }
- DO_PROFILE_INC(statcache_hits);
-
- TALLOC_FREE(smb_fname_rel->base_name);
- smb_fname_rel->base_name = talloc_memdup(
- smb_fname_rel, value.data, value.length);
- if (smb_fname_rel->base_name == NULL) {
- TALLOC_FREE(cache_key.data);
- return NT_STATUS_NO_MEMORY;
- }
-
- if (IS_VETO_PATH(dirfsp->conn, smb_fname_rel->base_name)) {
- DBG_DEBUG("veto files rejecting last component %s\n",
- smb_fname_str_dbg(smb_fname_rel));
- TALLOC_FREE(cache_key.data);
- return NT_STATUS_OBJECT_NAME_NOT_FOUND;
- }
-
- status = openat_pathref_fsp(dirfsp, smb_fname_rel);
- if (NT_STATUS_IS_OK(status)) {
- TALLOC_FREE(cache_key.data);
- return NT_STATUS_OK;
- }
-
- memcache_delete(NULL, GETREALFILENAME_CACHE, cache_key);
- }
-
-lookup:
- status = get_real_filename_at(
- dirfsp, smb_fname_rel->base_name, smb_fname_rel, &found_name);
- if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
- (ucf_flags & UCF_PREP_CREATEFILE)) {
- /*
- * dropbox
- */
- status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
- }
-
- if (NT_STATUS_IS_OK(status)) {
- TALLOC_FREE(smb_fname_rel->base_name);
- smb_fname_rel->base_name = found_name;
+ const char *prev = NULL;
- if (IS_VETO_PATH(dirfsp->conn, smb_fname_rel->base_name)) {
- DBG_DEBUG("veto files rejecting last component %s\n",
- smb_fname_str_dbg(smb_fname_rel));
- return NT_STATUS_OBJECT_NAME_NOT_FOUND;
- }
+ SMB_ASSERT((name_in <= slash) && (slash[0] == '/'));
- status = openat_pathref_fsp(dirfsp, smb_fname_rel);
- }
+ prev = strchr_m(name_in, '/');
- if (NT_STATUS_IS_OK(status) && (cache_key.data != NULL)) {
- DATA_BLOB value = {
- .data = (uint8_t *)smb_fname_rel->base_name,
- .length = strlen(smb_fname_rel->base_name) + 1,
- };
-
- memcache_add(NULL, GETREALFILENAME_CACHE, cache_key, value);
+ if (prev == slash) {
+ /* No previous slash */
+ return NULL;
}
- TALLOC_FREE(cache_key.data);
-
- return status;
-}
-
-static const char *previous_slash(const char *name_in, const char *slash)
-{
- const char *prev = name_in;
-
while (true) {
- const char *next = strchr_m(prev, '/');
-
- SMB_ASSERT(next != NULL); /* we have at least one slash */
+ const char *next = strchr_m(prev + 1, '/');
if (next == slash) {
- break;
+ return prev;
}
-
- prev = next+1;
- };
-
- if (prev == name_in) {
- /* no previous slash */
- return NULL;
+ prev = next;
}
- return prev;
+ return NULL; /* unreachable */
}
static char *symlink_target_path(
}
if (parent == NULL) {
- /* no previous slash */
- parent = name_in;
+ ret = talloc_asprintf(mem_ctx, "%s%s", substitute, p_unparsed);
+ } else {
+ ret = talloc_asprintf(mem_ctx,
+ "%.*s/%s%s",
+ (int)(parent - name_in),
+ name_in,
+ substitute,
+ p_unparsed);
}
- ret = talloc_asprintf(
- mem_ctx,
- "%.*s%s%s",
- (int)(parent - name_in),
- name_in,
- substitute,
- p_unparsed);
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;
}
connectpath, strlen(connectpath), abs_target_canon, &relative);
if (!in_share) {
DBG_DEBUG("wide link to %s\n", abs_target_canon);
- status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
+ status = (unparsed != 0) ? NT_STATUS_OBJECT_PATH_NOT_FOUND
+ : NT_STATUS_OBJECT_NAME_NOT_FOUND;
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,
- char **_substitute,
- size_t *_unparsed)
+ 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 reparse_data_buffer *symlink_err = NULL;
const bool posix = (ucf_flags & UCF_POSIX_PATHNAMES);
char *dirname = NULL;
const char *fname_rel = NULL;
bool ok;
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
- if (ucf_flags & UCF_DFS_PATHNAME) {
- /*
- * We've been given a raw DFS pathname.
- */
- char *pathname = NULL;
- DBG_DEBUG("Before dfs_filename_convert name_in: %s\n",
- name_in);
- status = dfs_filename_convert(mem_ctx,
- conn,
- ucf_flags,
- name_in,
- &pathname);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_DEBUG("dfs_filename_convert "
- "failed for name %s with %s\n",
- name_in,
- nt_errstr(status));
- return status;
- }
- ucf_flags &= ~UCF_DFS_PATHNAME;
- name_in = pathname;
- DBG_DEBUG("After dfs_filename_convert name_in: %s\n",
- name_in);
- }
+ SMB_ASSERT(!(ucf_flags & UCF_DFS_PATHNAME));
if (is_fake_file_path(name_in)) {
smb_fname = synthetic_smb_fname_split(mem_ctx, name_in, posix);
if (smb_fname == NULL) {
return NT_STATUS_NO_MEMORY;
}
- smb_fname->st = (SMB_STRUCT_STAT) { .st_ex_nlink = 1 };
+ smb_fname->st = (SMB_STRUCT_STAT){
+ .st_ex_nlink = 1,
+ .st_ex_mode = S_IFREG | 0644,
+ };
smb_fname->st.st_ex_btime =
(struct timespec){0, SAMBA_UTIME_OMIT};
smb_fname->st.st_ex_atime =
posix ? SMB_FILENAME_POSIX_PATH : 0,
&smb_dirname);
} else {
- char *substitute = NULL;
- size_t unparsed = 0;
-
status = normalize_filename_case(conn, dirname, ucf_flags);
if (!NT_STATUS_IS_OK(status)) {
DBG_ERR("normalize_filename_case %s failed: %s\n",
goto fail;
}
- status = openat_pathref_dirfsp_nosymlink(
- mem_ctx,
- conn,
- dirname,
- 0,
- posix,
- &smb_dirname,
- &unparsed,
- &substitute);
+ status = openat_pathref_fsp_nosymlink(mem_ctx,
+ conn,
+ conn->cwd_fsp,
+ dirname,
+ twrp,
+ posix,
+ &smb_dirname,
+ &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;
- size_t name_in_len = strlen(name_in);
- size_t dirname_len = strlen(dirname);
+ name_in_len = strlen(name_in);
+ dirname_len = strlen(dirname);
SMB_ASSERT(name_in_len >= dirname_len);
- *_substitute = substitute;
- *_unparsed = 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;
}
nt_errstr(status));
TALLOC_FREE(dirname);
- if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
- /* MS-DFS error must propagate back out. */
- goto fail;
- }
-
if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
/*
* Except ACCESS_DENIED, everything else leads
status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
goto fail;
}
+ smb_dirname->fsp->fsp_flags.is_directory = true;
/*
* Only look at bad last component values
goto fail;
}
- status = openat_pathref_fsp_case_insensitive(
- smb_dirname->fsp, smb_fname_rel, ucf_flags);
+ status = openat_pathref_fsp_lcomp(smb_dirname->fsp,
+ smb_fname_rel,
+ ucf_flags);
- if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
- VALID_STAT(smb_fname_rel->st) &&
- S_ISLNK(smb_fname_rel->st.st_ex_mode)) {
+ if (NT_STATUS_IS_OK(status) && S_ISLNK(smb_fname_rel->st.st_ex_mode)) {
/*
- * If we're on an MSDFS share, see if this is
- * an MSDFS link.
+ * Upper layers might need the link target. Here we
+ * still have the relname around, get the symlink err.
*/
- if (lp_host_msdfs() &&
- lp_msdfs_root(SNUM(conn)) &&
- is_msdfs_link(smb_dirname->fsp, smb_fname_rel))
- {
- status = NT_STATUS_PATH_NOT_COVERED;
+ 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(
+ smb_fname_rel->fsp->fsp_name),
+ nt_errstr(status));
goto fail;
}
-
-#if defined(WITH_SMB1SERVER)
- /*
- * In SMB1 posix mode, if this is a symlink,
- * allow access to the name with a NULL smb_fname->fsp.
- */
- if (ucf_flags & UCF_LCOMP_LNK_OK) {
- SMB_ASSERT(smb_fname_rel->fsp == NULL);
- SMB_ASSERT(streamname == NULL);
-
- smb_fname = full_path_from_dirfsp_atname(
- mem_ctx,
- smb_dirname->fsp,
- smb_fname_rel);
- if (smb_fname == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto fail;
- }
- goto done;
- }
-#endif
}
if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
goto done;
}
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_OPEN_RESTRICTION)) {
+ /* A vetoed file, pretend it's not there */
+ status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
if (!NT_STATUS_IS_OK(status)) {
goto fail;
}
done:
*_dirfsp = smb_dirname->fsp;
*_smb_fname = smb_fname;
+ *_symlink_err = symlink_err;
smb_fname_fsp_unlink(smb_fname_rel);
TALLOC_FREE(smb_fname_rel);
struct files_struct **_dirfsp,
struct smb_filename **_smb_fname)
{
- char *substitute = NULL;
- size_t unparsed = 0;
+ struct reparse_data_buffer *symlink_err = NULL;
+ struct symlink_reparse_struct *lnk = NULL;
NTSTATUS status;
char *target = NULL;
+ char *safe_target = NULL;
size_t symlink_redirects = 0;
next:
return NT_STATUS_OBJECT_PATH_NOT_FOUND;
}
- status = filename_convert_dirfsp_nosymlink(
- mem_ctx,
- conn,
- name_in,
- ucf_flags,
- twrp,
- _dirfsp,
- _smb_fname,
- &substitute,
- &unparsed);
+ status = filename_convert_dirfsp_nosymlink(mem_ctx,
+ conn,
+ name_in,
+ ucf_flags,
+ twrp,
+ _dirfsp,
+ _smb_fname,
+ &symlink_err);
+
+ if (NT_STATUS_IS_OK(status) && S_ISLNK((*_smb_fname)->st.st_ex_mode)) {
+ /*
+ * lcomp is a symlink
+ */
+ if (ucf_flags & UCF_LCOMP_LNK_OK) {
+ TALLOC_FREE(symlink_err);
+ return NT_STATUS_OK;
+ }
+ close_file_free(NULL, _dirfsp, ERROR_CLOSE);
+ status = NT_STATUS_STOPPED_ON_SYMLINK;
+ }
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(lnk->substitute_name, "msdfs:", 6))
+ {
+ TALLOC_FREE(*_smb_fname);
+ TALLOC_FREE(symlink_err);
+ return NT_STATUS_PATH_NOT_COVERED;
+ }
if (!lp_follow_symlinks(SNUM(conn))) {
- return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+ status = (lnk->unparsed_path_length == 0)
+ ? NT_STATUS_OBJECT_NAME_NOT_FOUND
+ : NT_STATUS_OBJECT_PATH_NOT_FOUND;
+ TALLOC_FREE(symlink_err);
+ return status;
}
/*
* resolve all symlinks locally.
*/
- status = safe_symlink_target_path(
- mem_ctx,
- conn->connectpath,
- name_in,
- substitute,
- unparsed,
- &target);
+ 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,
+ 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;
goto next;
}
-/*
- * Build the full path from a dirfsp and dirfsp relative name
- */
-struct smb_filename *full_path_from_dirfsp_atname(
- TALLOC_CTX *mem_ctx,
- const struct files_struct *dirfsp,
- const struct smb_filename *atname)
+char *full_path_from_dirfsp_at_basename(TALLOC_CTX *mem_ctx,
+ const struct files_struct *dirfsp,
+ const char *at_base_name)
{
- struct smb_filename *fname = NULL;
char *path = NULL;
if (dirfsp == dirfsp->conn->cwd_fsp ||
- ISDOT(dirfsp->fsp_name->base_name) ||
- atname->base_name[0] == '/')
- {
- path = talloc_strdup(mem_ctx, atname->base_name);
+ ISDOT(dirfsp->fsp_name->base_name) || at_base_name[0] == '/') {
+ path = talloc_strdup(mem_ctx, at_base_name);
} else {
- path = talloc_asprintf(mem_ctx, "%s/%s",
+ path = talloc_asprintf(mem_ctx,
+ "%s/%s",
dirfsp->fsp_name->base_name,
- atname->base_name);
+ at_base_name);
}
+
+ return path;
+}
+
+/*
+ * Build the full path from a dirfsp and dirfsp relative name
+ */
+struct smb_filename *
+full_path_from_dirfsp_atname(TALLOC_CTX *mem_ctx,
+ const struct files_struct *dirfsp,
+ const struct smb_filename *atname)
+{
+ struct smb_filename *fname = NULL;
+ char *path = NULL;
+
+ path = full_path_from_dirfsp_at_basename(mem_ctx,
+ dirfsp,
+ atname->base_name);
if (path == NULL) {
return NULL;
}