From 2f9e0f8d74b90a7258b22c68fd04480ab60e4ef2 Mon Sep 17 00:00:00 2001 From: Richard Lau Date: Wed, 30 Nov 2016 20:00:32 +0000 Subject: [PATCH] win: map ERROR_ELEVATION_REQUIRED to UV_EACCES uv_spawn() on Windows will fail with ERROR_ELEVATION_REQUIRED (740) if attempting to run an application that requires elevation. Add a Windows test that calls uv_spawn() with a helper .exe that requires elevated permissions. Test should either run successfully if run with Administrator privileges or fail with the mapped error. Refs: https://github.com/nodejs/node/issues/9464 --- src/win/error.c | 1 + test/elevation.c | 3 +++ test/test-error.c | 1 + test/test-list.h | 6 ++++++ test/test-spawn.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ uv.gyp | 25 +++++++++++++++++++++++-- 6 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 test/elevation.c diff --git a/src/win/error.c b/src/win/error.c index c512f35af979..642d1112e119 100644 --- a/src/win/error.c +++ b/src/win/error.c @@ -71,6 +71,7 @@ int uv_translate_sys_error(int sys_errno) { switch (sys_errno) { case ERROR_NOACCESS: return UV_EACCES; case WSAEACCES: return UV_EACCES; + case ERROR_ELEVATION_REQUIRED: return UV_EACCES; case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE; case WSAEADDRINUSE: return UV_EADDRINUSE; case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL; diff --git a/test/elevation.c b/test/elevation.c new file mode 100644 index 000000000000..11b7fad8ecaf --- /dev/null +++ b/test/elevation.c @@ -0,0 +1,3 @@ +int main(int argc, char **argv) { + return 0; +} diff --git a/test/test-error.c b/test/test-error.c index 4c4efa30cddd..ff53eb1d7779 100644 --- a/test/test-error.c +++ b/test/test-error.c @@ -53,6 +53,7 @@ TEST_IMPL(error_message) { TEST_IMPL(sys_error) { #if defined(_WIN32) ASSERT(uv_translate_sys_error(ERROR_NOACCESS) == UV_EACCES); + ASSERT(uv_translate_sys_error(ERROR_ELEVATION_REQUIRED) == UV_EACCES); ASSERT(uv_translate_sys_error(WSAEADDRINUSE) == UV_EADDRINUSE); ASSERT(uv_translate_sys_error(ERROR_BAD_PIPE) == UV_EPIPE); #else diff --git a/test/test-list.h b/test/test-list.h index be3f9069cc77..dce8d0aa24f8 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -230,6 +230,9 @@ TEST_DECLARE (spawn_fails) #ifndef _WIN32 TEST_DECLARE (spawn_fails_check_for_waitpid_cleanup) #endif +#ifdef _WIN32 +TEST_DECLARE (spawn_requires_elevation) +#endif TEST_DECLARE (spawn_exit_code) TEST_DECLARE (spawn_stdout) TEST_DECLARE (spawn_stdin) @@ -656,6 +659,9 @@ TASK_LIST_START TEST_ENTRY (spawn_fails) #ifndef _WIN32 TEST_ENTRY (spawn_fails_check_for_waitpid_cleanup) +#endif +#ifdef _WIN32 + TEST_ENTRY (spawn_requires_elevation) #endif TEST_ENTRY (spawn_exit_code) TEST_ENTRY (spawn_stdout) diff --git a/test/test-spawn.c b/test/test-spawn.c index 53a036969b62..fd64e523097c 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -215,6 +215,52 @@ TEST_IMPL(spawn_fails_check_for_waitpid_cleanup) { #endif +#ifdef _WIN32 +TEST_IMPL(spawn_requires_elevation) { + int r; + uv_fs_t req; + char path[1024]; + size_t path_size = 1024; + + /* Find helper elevation.exe -- Assumed in same location as test runner */ + r = uv_exepath(exepath, &exepath_size); + ASSERT(r == 0); + exepath[exepath_size] = '\0'; + snprintf(path, path_size, "%s\\..\\elevation.exe", exepath); + uv_loop_t* loop = uv_default_loop(); + ASSERT(0 == uv_fs_realpath(loop, &req, path, NULL)); + + /* + * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW() + */ + if (req.result == UV_ENOSYS) { + uv_fs_req_cleanup(&req); + RETURN_SKIP("realpath is not supported on Windows XP"); + } + + ASSERT(req.ptr != NULL); + + init_process_options("", fail_cb); + options.file = options.args[0] = req.ptr; + + printf("Launching %s\n", (char*) req.ptr); + r = uv_spawn(uv_default_loop(), &process, &options); + printf("r = %d, %s - %s\n", r, uv_err_name(r), uv_strerror(r)); + + /* + * Will either succeed or fail depending on whether test is being run with + * elevated permissions + */ + ASSERT(r == 0 || r == UV_EACCES); + uv_close((uv_handle_t*) &process, NULL); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif + + TEST_IMPL(spawn_exit_code) { int r; diff --git a/uv.gyp b/uv.gyp index b969a8cd5dad..bf1143ff0492 100644 --- a/uv.gyp +++ b/uv.gyp @@ -311,7 +311,6 @@ }], ] }, - { 'target_name': 'run-tests', 'type': 'executable', @@ -569,5 +568,27 @@ }, }, }, - ] + ], + 'conditions': [ + ['OS=="win"', { + 'targets': [ + { + 'target_name': 'elevation', + 'type': 'executable', + 'sources': [ + 'test/elevation.c' + ], + 'msvs_settings': { + 'VCLinkerTool': { + 'UACExecutionLevel': 2, # requireAdministrator + 'UACUIAccess': 'false', + }, + 'VCManifestTool': { + 'EmbedManifest': 'true', + } + }, + } + ], + }], + ], }