From 00c8d82d54da5f7eb9b80905a3a738c58480a493 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 13 Sep 2017 11:37:29 -0700 Subject: [PATCH] s3: modules: shadow_copy2: Cope with GETWD() failing inside CHDIR(). Fail the CHDIR(). Signed-off-by: Jeremy Allison --- source3/modules/vfs_shadow_copy2.c | 39 +++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index 6a123092a5e..93097891771 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -1519,21 +1519,27 @@ static int shadow_copy2_chown(vfs_handle_struct *handle, return ret; } -static void store_cwd_data(vfs_handle_struct *handle, +static int store_cwd_data(vfs_handle_struct *handle, const char *connectpath) { struct shadow_copy2_private *priv = NULL; struct smb_filename *cwd_fname = NULL; SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private, - return); + return -1); - TALLOC_FREE(priv->shadow_cwd); cwd_fname = SMB_VFS_NEXT_GETWD(handle, talloc_tos()); if (cwd_fname == NULL) { - smb_panic("getwd failed\n"); + return -1; } DBG_DEBUG("shadow cwd = %s\n", cwd_fname->base_name); + + /* + * Now we're modifying the priv data. Any + * failures here are terminal. + */ + + TALLOC_FREE(priv->shadow_cwd); priv->shadow_cwd = talloc_strdup(priv, cwd_fname->base_name); TALLOC_FREE(cwd_fname); if (priv->shadow_cwd == NULL) { @@ -1547,6 +1553,7 @@ static void store_cwd_data(vfs_handle_struct *handle, smb_panic("talloc failed\n"); } } + return 0; } static int shadow_copy2_chdir(vfs_handle_struct *handle, @@ -1560,6 +1567,7 @@ static int shadow_copy2_chdir(vfs_handle_struct *handle, char *conv = NULL; size_t rootpath_len = 0; struct smb_filename *conv_smb_fname = NULL; + struct smb_filename *saved_cwd_fname = NULL; if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle, @@ -1594,6 +1602,14 @@ static int shadow_copy2_chdir(vfs_handle_struct *handle, return -1; } + /* Save off the $cwd in case we need to restore on error. */ + saved_cwd_fname = SMB_VFS_NEXT_GETWD(handle, talloc_tos()); + if (saved_cwd_fname == NULL) { + TALLOC_FREE(conv); + TALLOC_FREE(conv_smb_fname); + return -1; + } + ret = SMB_VFS_NEXT_CHDIR(handle, conv_smb_fname); if (ret == -1) { saved_errno = errno; @@ -1606,12 +1622,25 @@ static int shadow_copy2_chdir(vfs_handle_struct *handle, TALLOC_FREE(conv); conv = snappath; } - store_cwd_data(handle, conv); + ret = store_cwd_data(handle, conv); + if (ret == -1) { + /* + * We must restore the original + * $cwd if the secondary operation + * returned an error. + */ + int sret = SMB_VFS_NEXT_CHDIR(handle, saved_cwd_fname); + if (sret == -1) { + smb_panic("saved cwd chdir failed\n"); + } + saved_errno = errno; + } } TALLOC_FREE(stripped); TALLOC_FREE(conv); TALLOC_FREE(conv_smb_fname); + TALLOC_FREE(saved_cwd_fname); if (saved_errno != 0) { errno = saved_errno; -- 2.11.0