From 650db1f46e6a3f1f62088a4e06f15ae3be9fe8d6 Mon Sep 17 00:00:00 2001 From: Mike Gelfand Date: Tue, 20 Oct 2015 21:22:19 +0000 Subject: [PATCH] #5802: Don't make assumptions of remote path validity in transmission-remote Defer validity checks until path gets to the remote side, where they actually make sense. Add simple checks for download directory path to ensure it's not relative, since one cannot know what current working directory of the remote process is. --- daemon/remote.c | 47 ++---------------------------------- libtransmission/file-posix.c | 8 ++++++ libtransmission/file-test.c | 44 +++++++++++++++++++++++++++++++++ libtransmission/file-win32.c | 17 +++++++++++++ libtransmission/file.h | 11 +++++++++ libtransmission/rpcimpl.c | 16 +++++++++--- 6 files changed, 95 insertions(+), 48 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index 2d62fdd8d..f5f2da31b 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -490,43 +490,6 @@ static char * netrc = NULL; static char * sessionId = NULL; static bool UseSSL = false; -static char* -tr_getcwd (void) -{ - char * result; - tr_error * error = NULL; - - result = tr_sys_dir_get_current (&error); - - if (result == NULL) - { - fprintf (stderr, "getcwd error: \"%s\"", error->message); - tr_error_free (error); - result = tr_strdup (""); - } - - return result; -} - -static char* -absolutify (const char * path) -{ - char * buf; - - if (*path == '/') - { - buf = tr_strdup (path); - } - else - { - char * cwd = tr_getcwd (); - buf = tr_buildPath (cwd, path, NULL); - tr_free (cwd); - } - - return buf; -} - static char* getEncodedMetainfo (const char * filename) { @@ -2253,14 +2216,8 @@ processArgs (const char * rpcurl, int argc, const char ** argv) } case 'w': { - char * path = absolutify (optarg); - if (tadd) - tr_variantDictAddStr (tr_variantDictFind (tadd, TR_KEY_arguments), TR_KEY_download_dir, path); - else { - tr_variant * args = ensure_sset (&sset); - tr_variantDictAddStr (args, TR_KEY_download_dir, path); - } - tr_free (path); + tr_variant * args = tadd ? tr_variantDictFind (tadd, TR_KEY_arguments) : ensure_sset (&sset); + tr_variantDictAddStr (args, TR_KEY_download_dir, optarg); break; } case 850: diff --git a/libtransmission/file-posix.c b/libtransmission/file-posix.c index 95f147aee..1fbc35a71 100644 --- a/libtransmission/file-posix.c +++ b/libtransmission/file-posix.c @@ -258,6 +258,14 @@ tr_sys_path_get_info (const char * path, return ret; } +bool +tr_sys_path_is_relative (const char * path) +{ + assert (path != NULL); + + return path[0] != '/'; +} + bool tr_sys_path_is_same (const char * path1, const char * path2, diff --git a/libtransmission/file-test.c b/libtransmission/file-test.c index 30b11157d..dcbc84ca8 100644 --- a/libtransmission/file-test.c +++ b/libtransmission/file-test.c @@ -320,6 +320,49 @@ test_path_exists (void) return 0; } +static int +test_path_is_relative (void) +{ + check (tr_sys_path_is_relative ("")); + check (tr_sys_path_is_relative (".")); + check (tr_sys_path_is_relative ("..")); + check (tr_sys_path_is_relative ("x")); + check (tr_sys_path_is_relative ("\\")); + check (tr_sys_path_is_relative (":")); + +#ifdef _WIN32 + + check (tr_sys_path_is_relative ("/")); + check (tr_sys_path_is_relative ("//x")); + check (tr_sys_path_is_relative ("\\x")); + check (tr_sys_path_is_relative ("\\x\\y")); + check (tr_sys_path_is_relative ("C:x")); + check (tr_sys_path_is_relative ("C:x\\y")); + + check (!tr_sys_path_is_relative ("\\\\")); + check (!tr_sys_path_is_relative ("\\\\x")); + check (!tr_sys_path_is_relative ("\\\\x\\y")); + check (!tr_sys_path_is_relative ("\\\\.\\x")); + + check (!tr_sys_path_is_relative ("a:")); + check (!tr_sys_path_is_relative ("a:\\")); + check (!tr_sys_path_is_relative ("a:/")); + check (!tr_sys_path_is_relative ("Z:")); + check (!tr_sys_path_is_relative ("Z:\\")); + check (!tr_sys_path_is_relative ("Z:/")); + +#else /* _WIN32 */ + + check (!tr_sys_path_is_relative ("/")); + check (!tr_sys_path_is_relative ("/x")); + check (!tr_sys_path_is_relative ("/x/y")); + check (!tr_sys_path_is_relative ("//x")); + +#endif /* _WIN32 */ + + return 0; +} + static int test_path_is_same (void) { @@ -1401,6 +1444,7 @@ main (void) { test_get_info, test_path_exists, + test_path_is_relative, test_path_is_same, test_path_resolve, test_path_basename_dirname, diff --git a/libtransmission/file-win32.c b/libtransmission/file-win32.c index 2bf12a677..45fd3cb91 100644 --- a/libtransmission/file-win32.c +++ b/libtransmission/file-win32.c @@ -8,6 +8,7 @@ */ #include +#include /* isalpha () */ #include /* _splitpath_s (), _makepath_s () */ #include /* SHCreateDirectoryEx () */ @@ -327,6 +328,22 @@ tr_sys_path_get_info (const char * path, return ret; } +bool +tr_sys_path_is_relative (const char * path) +{ + assert (path != NULL); + + /* UNC path: `\\...`. */ + if (path[0] == '\\' && path[1] == '\\') + return false; + + /* Local path: `X:` or `X:\...`. */ + if (isalpha (path[0]) && path[1] == ':' && (path[2] == '\0' || path[2] == '\\' || path[2] == '/')) + return false; + + return true; +} + bool tr_sys_path_is_same (const char * path1, const char * path2, diff --git a/libtransmission/file.h b/libtransmission/file.h index c5b544d38..7d6c7dba6 100644 --- a/libtransmission/file.h +++ b/libtransmission/file.h @@ -156,6 +156,17 @@ bool tr_sys_path_get_info (const char * path, bool tr_sys_path_exists (const char * path, struct tr_error ** error); +/** + * @brief Check whether path is relative. + * + * This function only analyzes the string, so no error reporting is needed. + * + * @param[in] path Path to file or directory. + * + * @return `True` if path is relative, `false` otherwise + */ +bool tr_sys_path_is_relative (const char * path); + /** * @brief Test to see if the two filenames point to the same file. * diff --git a/libtransmission/rpcimpl.c b/libtransmission/rpcimpl.c index 9d514a2d4..2184927b4 100644 --- a/libtransmission/rpcimpl.c +++ b/libtransmission/rpcimpl.c @@ -1343,6 +1343,9 @@ torrentSetLocation (tr_session * session, if (!tr_variantDictFindStr (args_in, TR_KEY_location, &location, NULL)) return "no location"; + if (tr_sys_path_is_relative (location)) + return "new location path is not absolute"; + bool move; int i, torrentCount; tr_torrent ** torrents = getTorrents (session, args_in, &torrentCount); @@ -1711,10 +1714,17 @@ torrentAdd (tr_session * session, if (!filename && !metainfo_base64) return "no filename or metainfo specified"; + const char * download_dir = NULL; + + if (tr_variantDictFindStr (args_in, TR_KEY_download_dir, &download_dir, NULL)) + { + if (tr_sys_path_is_relative (download_dir)) + return "download directory path is not absolute"; + } + int64_t i; bool boolVal; tr_variant * l; - const char * str; const char * cookies = NULL; tr_ctor * ctor = tr_ctorNew (session); @@ -1722,8 +1732,8 @@ torrentAdd (tr_session * session, tr_variantDictFindStr (args_in, TR_KEY_cookies, &cookies, NULL); - if (tr_variantDictFindStr (args_in, TR_KEY_download_dir, &str, NULL)) - tr_ctorSetDownloadDir (ctor, TR_FORCE, str); + if (download_dir != NULL) + tr_ctorSetDownloadDir (ctor, TR_FORCE, download_dir); if (tr_variantDictFindBool (args_in, TR_KEY_paused, &boolVal)) tr_ctorSetPaused (ctor, TR_FORCE, boolVal);