]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
smbd: strip @GMT token in canonicalize_snapshot_path()
authorRalph Boehme <slow@samba.org>
Thu, 30 Apr 2020 13:24:44 +0000 (15:24 +0200)
committerJeremy Allison <jra@samba.org>
Tue, 5 May 2020 19:18:43 +0000 (19:18 +0000)
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 <slow@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
source3/modules/vfs_shadow_copy2.c
source3/smbd/filename.c
source3/smbd/proto.h
source3/smbd/statcache.c

index b33a6f64223eccd52e63ef9dde57f12b6664eb4f..53fee915c37218e8e1acdcb95d86c7210fd11337 100644 (file)
@@ -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;
index b93c0ee6f45b57901b0bc01877e01239b972ef58..ca5a7a66282598c33ed898bbe17a28aa8f560320 100644 (file)
@@ -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);
        }
 
index b0b6e2981c3757e0b2eaf6ba013f53223a23da9f..20b5c43f139281781424c3b831b81d596d5f3453 100644 (file)
@@ -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);
index 3176ca06a71d92595b309e280a0c43a1f969fa1d..63f41db1b1b9f193686b3349cdbab58389124630 100644 (file)
@@ -28,6 +28,9 @@
 #include "smbprofile.h"
 #include <tdb.h>
 
+#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",