From: Ralph Boehme Date: Thu, 30 Apr 2020 13:24:44 +0000 (+0200) Subject: smbd: strip @GMT token in canonicalize_snapshot_path() X-Git-Tag: ldb-2.2.0~659 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=6e364c545384c5da4a0f0f0536c40394aa2e2a97;p=thirdparty%2Fsamba.git smbd: strip @GMT token in canonicalize_snapshot_path() smbd and all previous-versions implementing VFS modules have been patched to work with struct smb_filename.NTTIME twrp, so we can now safely strip @GMT tokens from paths. This also means that "@GMT-something/foo" and "foo" will both come out as "foo", so we have to take care of the stat-cache now and change it to take and use an additional twrp arg. At the same time remove @GMT stripping from shadow_copy2. In theory this could be made a seperate commit, but due to the absolute path and pstripped logic, it felt too cumbersome to attempt this. Leaving the exercize of removing the now unneeded stripped logic to a future patchset. Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison --- diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index b33a6f64223..53fee915c37 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -592,16 +592,8 @@ static bool shadow_copy2_strip_snapshot_internal(TALLOC_CTX *mem_ctx, char **psnappath, bool *_already_converted) { - const char *orig_name = smb_fname->base_name; - struct tm tm; - time_t timestamp = 0; - const char *p; - char *q; char *stripped = NULL; - size_t rest_len, dst_len; struct shadow_copy2_private *priv; - ptrdiff_t len_before_gmt; - const char *name = orig_name; char *abs_path = NULL; bool ret = true; bool already_converted = false; @@ -610,20 +602,19 @@ static bool shadow_copy2_strip_snapshot_internal(TALLOC_CTX *mem_ctx, SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private, return false); - DEBUG(10, (__location__ ": enter path '%s'\n", name)); + DBG_DEBUG("Enter path '%s'\n", smb_fname_str_dbg(smb_fname)); if (_already_converted != NULL) { *_already_converted = false; } - abs_path = make_path_absolute(mem_ctx, priv, name); + abs_path = make_path_absolute(mem_ctx, priv, smb_fname->base_name); if (abs_path == NULL) { ret = false; goto out; } - name = abs_path; - DEBUG(10, (__location__ ": abs path '%s'\n", name)); + DBG_DEBUG("abs path '%s'\n", abs_path); err = check_for_converted_path(mem_ctx, handle, @@ -652,106 +643,19 @@ static bool shadow_copy2_strip_snapshot_internal(TALLOC_CTX *mem_ctx, *ptimestamp = nt_time_to_unix(smb_fname->twrp); } - /* - * From here we're only looking to strip an - * SMB-layer @GMT- token. - */ - - p = strstr_m(name, "@GMT-"); - if (p == NULL) { - DEBUG(11, ("@GMT not found\n")); - goto out; - } - if ((p > name) && (p[-1] != '/')) { - /* the GMT-token does not start a path-component */ - DEBUG(10, ("not at start, p=%p, name=%p, p[-1]=%d\n", - p, name, (int)p[-1])); - goto out; - } - - len_before_gmt = p - name; - - q = strptime(p, GMT_FORMAT, &tm); - if (q == NULL) { - DEBUG(10, ("strptime failed\n")); - goto out; - } - tm.tm_isdst = -1; - timestamp = timegm(&tm); - if (timestamp == (time_t)-1) { - DEBUG(10, ("timestamp==-1\n")); - goto out; - } - if (q[0] == '\0') { - /* - * The name consists of only the GMT token or the GMT - * token is at the end of the path. XP seems to send - * @GMT- at the end under certain circumstances even - * with a path prefix. - */ - if (pstripped != NULL) { - if (len_before_gmt > 1) { - /* - * There is a path (and not only a slash) - * before the @GMT-. Remove the trailing - * slash character. - */ - len_before_gmt -= 1; - } - stripped = talloc_strndup(mem_ctx, name, - len_before_gmt); - if (stripped == NULL) { - ret = false; - goto out; - } - if (orig_name[0] != '/') { - if (make_relative_path(priv->shadow_cwd, - stripped) == false) { - DEBUG(10, (__location__ ": path '%s' " - "doesn't start with cwd '%s'\n", - stripped, priv->shadow_cwd)); - ret = false; - errno = ENOENT; - goto out; - } - } - *pstripped = stripped; - } - *ptimestamp = timestamp; - goto out; - } - if (q[0] != '/') { - /* - * It is not a complete path component, i.e. the path - * component continues after the gmt-token. - */ - DEBUG(10, ("q[0] = %d\n", (int)q[0])); - goto out; - } - q += 1; - - rest_len = strlen(q); - dst_len = len_before_gmt + rest_len; - if (pstripped != NULL) { - stripped = talloc_array(mem_ctx, char, dst_len+1); + stripped = talloc_strdup(mem_ctx, abs_path); if (stripped == NULL) { ret = false; goto out; } - if (p > name) { - memcpy(stripped, name, len_before_gmt); - } - if (rest_len > 0) { - memcpy(stripped + len_before_gmt, q, rest_len); - } - stripped[dst_len] = '\0'; - if (orig_name[0] != '/') { - if (make_relative_path(priv->shadow_cwd, - stripped) == false) { - DEBUG(10, (__location__ ": path '%s' " + + if (smb_fname->base_name[0] != '/') { + ret = make_relative_path(priv->shadow_cwd, stripped); + if (!ret) { + DBG_DEBUG("Path '%s' " "doesn't start with cwd '%s'\n", - stripped, priv->shadow_cwd)); + stripped, priv->shadow_cwd); ret = false; errno = ENOENT; goto out; diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c index b93c0ee6f45..ca5a7a66282 100644 --- a/source3/smbd/filename.c +++ b/source3/smbd/filename.c @@ -369,36 +369,14 @@ NTSTATUS canonicalize_snapshot_path(struct smb_filename *smb_fname, { char *startp = strchr_m(smb_fname->base_name, '@'); char *endp = NULL; + char *tmp = NULL; struct tm tm; time_t t; + NTTIME nt; NTSTATUS status; if (twrp != 0) { - struct tm *ptm = NULL; - char *twrp_name = NULL; - - t = nt_time_to_unix(twrp); - ptm = gmtime_r(&t, &tm); - - twrp_name = talloc_asprintf( - smb_fname, - "@GMT-%04u.%02u.%02u-%02u.%02u.%02u/%s", - ptm->tm_year + 1900, - ptm->tm_mon + 1, - ptm->tm_mday, - ptm->tm_hour, - ptm->tm_min, - ptm->tm_sec, - smb_fname->base_name); - if (twrp_name == NULL) { - return NT_STATUS_NO_MEMORY; - } - - TALLOC_FREE(smb_fname->base_name); - smb_fname->base_name = twrp_name; - smb_fname->twrp = twrp; - return NT_STATUS_OK; } if (startp == NULL) { @@ -436,9 +414,25 @@ NTSTATUS canonicalize_snapshot_path(struct smb_filename *smb_fname, return status; } - tm.tm_isdst = -1; - t = timegm(&tm); - unix_to_nt_time(&smb_fname->twrp, t); + startp = smb_fname->base_name + GMT_NAME_LEN; + if (startp[0] == '/') { + startp++; + } + + tmp = talloc_strdup(smb_fname, startp); + if (tmp == NULL) { + return NT_STATUS_NO_MEMORY; + } + + TALLOC_FREE(smb_fname->base_name); + smb_fname->base_name = tmp; + + if (smb_fname->twrp == 0) { + tm.tm_isdst = -1; + t = timegm(&tm); + unix_to_nt_time(&nt, t); + smb_fname->twrp = nt; + } return NT_STATUS_OK; } @@ -931,6 +925,7 @@ static NTSTATUS unix_convert_step(struct uc_state *state) if(!state->component_was_mangled && !state->name_has_wildcard) { stat_cache_add(state->orig_path, state->dirpath, + state->smb_fname->twrp, state->conn->case_sensitive); } @@ -1132,6 +1127,7 @@ NTSTATUS unix_convert(TALLOC_CTX *mem_ctx, &state->smb_fname->base_name, &state->dirpath, &state->name, + state->smb_fname->twrp, &state->smb_fname->st); if (found) { goto done; @@ -1188,6 +1184,7 @@ NTSTATUS unix_convert(TALLOC_CTX *mem_ctx, /* Add the path (not including the stream) to the cache. */ stat_cache_add(state->orig_path, state->smb_fname->base_name, + state->smb_fname->twrp, state->conn->case_sensitive); DBG_DEBUG("Conversion of base_name finished " "[%s] -> [%s]\n", @@ -1350,6 +1347,7 @@ NTSTATUS unix_convert(TALLOC_CTX *mem_ctx, if(!state->component_was_mangled && !state->name_has_wildcard) { stat_cache_add(state->orig_path, state->smb_fname->base_name, + state->smb_fname->twrp, state->conn->case_sensitive); } diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h index b0b6e2981c3..20b5c43f139 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -1169,12 +1169,14 @@ ssize_t message_push_string(uint8_t **outbuf, const char *str, int flags); void stat_cache_add( const char *full_orig_name, const char *translated_path, + NTTIME twrp, bool case_sensitive); bool stat_cache_lookup(connection_struct *conn, bool posix_paths, char **pp_name, char **pp_dirpath, char **pp_start, + NTTIME twrp, SMB_STRUCT_STAT *pst); void smbd_send_stat_cache_delete_message(struct messaging_context *msg_ctx, const char *name); diff --git a/source3/smbd/statcache.c b/source3/smbd/statcache.c index 3176ca06a71..63f41db1b1b 100644 --- a/source3/smbd/statcache.c +++ b/source3/smbd/statcache.c @@ -28,6 +28,9 @@ #include "smbprofile.h" #include +#define STAT_CACHE_TWRP_TOKEN "%016" PRIx64 "@%s" +#define STAT_CACHE_TWRP_TOKEN_LEN 17 + /**************************************************************************** Stat cache code used in unix_convert. *****************************************************************************/ @@ -46,6 +49,7 @@ void stat_cache_add( const char *full_orig_name, const char *translated_path_in, + NTTIME twrp, bool case_sensitive) { size_t translated_path_length; @@ -67,7 +71,10 @@ void stat_cache_add( const char *full_orig_name, return; } - translated_path = talloc_strdup(ctx, translated_path_in); + translated_path = talloc_asprintf(ctx, + STAT_CACHE_TWRP_TOKEN, + twrp, + translated_path_in); if (translated_path == NULL) { return; } @@ -95,9 +102,23 @@ void stat_cache_add( const char *full_orig_name, } if(case_sensitive) { - original_path = talloc_strdup(ctx,full_orig_name); + original_path = talloc_asprintf(ctx, + STAT_CACHE_TWRP_TOKEN, + twrp, + full_orig_name); } else { - original_path = talloc_strdup_upper(ctx,full_orig_name); + char *upper = NULL; + + upper = talloc_strdup_upper(ctx, full_orig_name); + if (upper == NULL) { + TALLOC_FREE(translated_path); + return; + } + original_path = talloc_asprintf(ctx, + STAT_CACHE_TWRP_TOKEN, + twrp, + upper); + TALLOC_FREE(upper); } if (!original_path) { @@ -179,6 +200,7 @@ bool stat_cache_lookup(connection_struct *conn, char **pp_name, char **pp_dirpath, char **pp_start, + NTTIME twrp, SMB_STRUCT_STAT *pst) { char *chk_name; @@ -213,14 +235,27 @@ bool stat_cache_lookup(connection_struct *conn, } if (conn->case_sensitive) { - chk_name = talloc_strdup(ctx,name); + chk_name = talloc_asprintf(ctx, + STAT_CACHE_TWRP_TOKEN, + twrp, + name); if (!chk_name) { DEBUG(0, ("stat_cache_lookup: strdup failed!\n")); return False; } } else { - chk_name = talloc_strdup_upper(ctx,name); + char *upper = NULL; + + upper = talloc_strdup_upper(ctx,name); + if (upper == NULL) { + DBG_ERR("talloc_strdup_upper failed!\n"); + return False; + } + chk_name = talloc_asprintf(ctx, + STAT_CACHE_TWRP_TOKEN, + twrp, + upper); if (!chk_name) { DEBUG(0, ("stat_cache_lookup: talloc_strdup_upper failed!\n")); return False; @@ -278,18 +313,23 @@ bool stat_cache_lookup(connection_struct *conn, } } - translated_path = talloc_strdup(ctx,(char *)data_val.data); + SMB_ASSERT(data_val.length >= STAT_CACHE_TWRP_TOKEN_LEN); + + translated_path = talloc_strdup( + ctx,(char *)data_val.data + STAT_CACHE_TWRP_TOKEN_LEN); if (!translated_path) { smb_panic("talloc failed"); } - translated_path_length = data_val.length - 1; + translated_path_length = data_val.length - 1 - STAT_CACHE_TWRP_TOKEN_LEN; DEBUG(10,("stat_cache_lookup: lookup succeeded for name [%s] " "-> [%s]\n", chk_name, translated_path )); DO_PROFILE_INC(statcache_hits); - ZERO_STRUCT(smb_fname); - smb_fname.base_name = translated_path; + smb_fname = (struct smb_filename) { + .base_name = translated_path, + .twrp = twrp, + }; if (posix_paths) { ret = SMB_VFS_LSTAT(conn, &smb_fname); @@ -376,9 +416,19 @@ void smbd_send_stat_cache_delete_message(struct messaging_context *msg_ctx, void stat_cache_delete(const char *name) { - char *lname = talloc_strdup_upper(talloc_tos(), name); + char *upper = talloc_strdup_upper(talloc_tos(), name); + char *lname = NULL; + + if (upper == NULL) { + return; + } - if (!lname) { + lname = talloc_asprintf(talloc_tos(), + STAT_CACHE_TWRP_TOKEN, + (uintmax_t)0, + upper); + TALLOC_FREE(upper); + if (lname == NULL) { return; } DEBUG(10,("stat_cache_delete: deleting name [%s] -> %s\n",