From 8daa83a594a2e98f39d764422bfbdbc62c9efd44 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 19:20:00 +0200 Subject: Adding upstream version 2:4.20.0+dfsg. Signed-off-by: Daniel Baumann --- source3/lib/filename_util.c | 406 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 406 insertions(+) create mode 100644 source3/lib/filename_util.c (limited to 'source3/lib/filename_util.c') diff --git a/source3/lib/filename_util.c b/source3/lib/filename_util.c new file mode 100644 index 0000000..3f8e903 --- /dev/null +++ b/source3/lib/filename_util.c @@ -0,0 +1,406 @@ +/* + Unix SMB/CIFS implementation. + Filename utility functions. + Copyright (C) Tim Prouty 2009 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include "includes.h" + +/** + * XXX: This is temporary and there should be no callers of this outside of + * this file once smb_filename is plumbed through all path based operations. + * The one legitimate caller currently is smb_fname_str_dbg(), which this + * could be made static for. + */ +NTSTATUS get_full_smb_filename(TALLOC_CTX *ctx, + const struct smb_filename *smb_fname, + char **full_name) +{ + if (smb_fname->stream_name) { + /* stream_name must always be NULL if there is no stream. */ + SMB_ASSERT(smb_fname->stream_name[0] != '\0'); + + *full_name = talloc_asprintf(ctx, "%s%s", smb_fname->base_name, + smb_fname->stream_name); + } else { + *full_name = talloc_strdup(ctx, smb_fname->base_name); + } + + if (!*full_name) { + return NT_STATUS_NO_MEMORY; + } + + return NT_STATUS_OK; +} + +/** + * There are actually legitimate callers of this such as functions that + * enumerate streams using the vfs_streaminfo interface and then want to + * operate on each stream. + */ +struct smb_filename *synthetic_smb_fname(TALLOC_CTX *mem_ctx, + const char *base_name, + const char *stream_name, + const SMB_STRUCT_STAT *psbuf, + NTTIME twrp, + uint32_t flags) +{ + /* Setup the base_name/stream_name. */ + + struct smb_filename smb_fname_loc = { + .base_name = discard_const_p(char, base_name), + .stream_name = discard_const_p(char, stream_name), + .flags = flags, + .twrp = twrp, + }; + + /* Copy the psbuf if one was given. */ + if (psbuf) + smb_fname_loc.st = *psbuf; + + /* Let cp_smb_filename() do the heavy lifting. */ + return cp_smb_filename(mem_ctx, &smb_fname_loc); +} + +/** + * Utility function used by VFS calls that must *NOT* operate + * on a stream filename, only the base_name. + */ +struct smb_filename *cp_smb_filename_nostream(TALLOC_CTX *mem_ctx, + const struct smb_filename *smb_fname_in) +{ + struct smb_filename smb_fname_loc = *smb_fname_in; + struct smb_filename *smb_fname = NULL; + + smb_fname_loc.stream_name = NULL; + + smb_fname = cp_smb_filename(mem_ctx, &smb_fname_loc); + return smb_fname; +} + +/** + * There are a few legitimate users of this. + */ +struct smb_filename *synthetic_smb_fname_split(TALLOC_CTX *ctx, + const char *fname, + bool posix_path) +{ + char *stream_name = NULL; + char *base_name = NULL; + struct smb_filename *ret; + bool ok; + + if (posix_path) { + /* No stream name looked for. */ + return synthetic_smb_fname(ctx, + fname, + NULL, + NULL, + 0, + SMB_FILENAME_POSIX_PATH); + } + + ok = split_stream_filename(ctx, + fname, + &base_name, + &stream_name); + if (!ok) { + return NULL; + } + + ret = synthetic_smb_fname(ctx, + base_name, + stream_name, + NULL, + 0, + 0); + TALLOC_FREE(base_name); + TALLOC_FREE(stream_name); + return ret; +} + +/** + * Return a string using the talloc_tos() + */ +const char *smb_fname_str_dbg(const struct smb_filename *smb_fname) +{ + char *fname = NULL; + time_t t; + struct tm tm; + struct tm *ptm = NULL; + fstring tstr; + ssize_t slen; + NTSTATUS status; + + if (smb_fname == NULL) { + return ""; + } + status = get_full_smb_filename(talloc_tos(), smb_fname, &fname); + if (!NT_STATUS_IS_OK(status)) { + return ""; + } + if (smb_fname->twrp == 0) { + return fname; + } + + t = nt_time_to_unix(smb_fname->twrp); + ptm = gmtime_r(&t, &tm); + if (ptm == NULL) { + return ""; + } + + slen = strftime(tstr, sizeof(tstr), GMT_FORMAT, &tm); + if (slen == 0) { + return ""; + } + + fname = talloc_asprintf_append_buffer( + fname, " {%s}", tstr); + if (fname == NULL) { + return ""; + } + return fname; +} + +/** + * Return a debug string of the path name of an fsp using the talloc_tos(). + */ +const char *fsp_str_dbg(const struct files_struct *fsp) +{ + const char *name = NULL; + + name = smb_fname_str_dbg(fsp->fsp_name); + if (name == NULL) { + return ""; + } + + return name; +} + +/** + * Create a debug string for the fnum of an fsp. + * + * This is allocated to talloc_tos() or a string constant + * in certain corner cases. The returned string should + * hence not be free'd directly but only via the talloc stack. + */ +const char *fsp_fnum_dbg(const struct files_struct *fsp) +{ + char *str; + + if (fsp == NULL) { + return "fnum [fsp is NULL]"; + } + + if (fsp->fnum == FNUM_FIELD_INVALID) { + return "fnum [invalid value]"; + } + + str = talloc_asprintf(talloc_tos(), "fnum %"PRIu64, fsp->fnum); + if (str == NULL) { + DEBUG(1, ("%s: talloc_asprintf failed\n", __FUNCTION__)); + return "fnum [talloc failed!]"; + } + + return str; +} + +struct smb_filename *cp_smb_filename(TALLOC_CTX *mem_ctx, + const struct smb_filename *in) +{ + struct smb_filename *out; + size_t base_len = 0; + size_t stream_len = 0; + int num = 0; + + /* stream_name must always be NULL if there is no stream. */ + if (in->stream_name) { + SMB_ASSERT(in->stream_name[0] != '\0'); + } + + if (in->base_name != NULL) { + base_len = strlen(in->base_name) + 1; + num += 1; + } + if (in->stream_name != NULL) { + stream_len = strlen(in->stream_name) + 1; + num += 1; + } + + out = talloc_pooled_object(mem_ctx, struct smb_filename, + num, stream_len + base_len); + if (out == NULL) { + return NULL; + } + ZERO_STRUCTP(out); + + /* + * The following allocations cannot fail as we + * pre-allocated space for them in the out pooled + * object. + */ + if (in->base_name != NULL) { + out->base_name = talloc_memdup( + out, in->base_name, base_len); + talloc_set_name_const(out->base_name, + out->base_name); + } + if (in->stream_name != NULL) { + out->stream_name = talloc_memdup( + out, in->stream_name, stream_len); + talloc_set_name_const(out->stream_name, + out->stream_name); + } + out->flags = in->flags; + out->st = in->st; + out->twrp = in->twrp; + return out; +} + +static void assert_valid_stream_smb_fname(const struct smb_filename *smb_fname) +{ + /* stream_name must always be NULL if there is no stream. */ + if (smb_fname->stream_name) { + SMB_ASSERT(smb_fname->stream_name[0] != '\0'); + } + + if (smb_fname->flags & SMB_FILENAME_POSIX_PATH) { + SMB_ASSERT(smb_fname->stream_name == NULL); + } +} + +/**************************************************************************** + Simple check to determine if a smb_fname is a real named stream or the + default stream. + ***************************************************************************/ + +bool is_ntfs_stream_smb_fname(const struct smb_filename *smb_fname) +{ + assert_valid_stream_smb_fname(smb_fname); + + return (smb_fname->stream_name != NULL); +} + +/**************************************************************************** + Simple check to determine if a smb_fname is pointing to a normal file or + a named stream that is not the default stream "::$DATA". + + foo -> false + foo::$DATA -> false + foo:bar -> true + foo:bar:$DATA -> true + + ***************************************************************************/ + +bool is_named_stream(const struct smb_filename *smb_fname) +{ + assert_valid_stream_smb_fname(smb_fname); + + if (smb_fname->stream_name == NULL) { + return false; + } + + if (strequal_m(smb_fname->stream_name, "::$DATA")) { + return false; + } + + return true; +} + +/**************************************************************************** + Returns true if the filename's stream == "::$DATA" + ***************************************************************************/ +bool is_ntfs_default_stream_smb_fname(const struct smb_filename *smb_fname) +{ + assert_valid_stream_smb_fname(smb_fname); + + if (smb_fname->stream_name == NULL) { + return false; + } + + return strequal_m(smb_fname->stream_name, "::$DATA"); +} + +/**************************************************************************** + Filter out Windows invalid EA names (list probed from Windows 2012). +****************************************************************************/ + +static const char bad_ea_name_chars[] = "\"*+,/:;<=>?[\\]|"; + +bool is_invalid_windows_ea_name(const char *name) +{ + int i; + /* EA name is pulled as ascii so we can examine + individual bytes here. */ + for (i = 0; name[i] != 0; i++) { + int val = (name[i] & 0xff); + if (val < ' ' || strchr(bad_ea_name_chars, val)) { + return true; + } + } + return false; +} + +bool ea_list_has_invalid_name(struct ea_list *ea_list) +{ + for (;ea_list; ea_list = ea_list->next) { + if (is_invalid_windows_ea_name(ea_list->ea.name)) { + return true; + } + } + return false; +} + +/**************************************************************************** + Split an incoming name into tallocd filename and stream components. + Returns true on success, false on out of memory. +****************************************************************************/ + +bool split_stream_filename(TALLOC_CTX *ctx, + const char *filename_in, + char **filename_out, + char **streamname_out) +{ + const char *stream_name = NULL; + char *stream_out = NULL; + char *file_out = NULL; + + stream_name = strchr_m(filename_in, ':'); + + if (stream_name) { + stream_out = talloc_strdup(ctx, stream_name); + if (stream_out == NULL) { + return false; + } + file_out = talloc_strndup(ctx, + filename_in, + PTR_DIFF(stream_name, filename_in)); + } else { + file_out = talloc_strdup(ctx, filename_in); + } + + if (file_out == NULL) { + TALLOC_FREE(stream_out); + return false; + } + + if (filename_out) { + *filename_out = file_out; + } + if (streamname_out) { + *streamname_out = stream_out; + } + return true; +} -- cgit v1.2.3