From 8d0b3d46b797a978f0b84128accfe3f2e01198b2 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 | 23 +++++++++++++++++++++++ test/test-error.c | 1 + test/test-list.h | 6 ++++++ test/test-spawn.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++ uv.gyp | 25 ++++++++++++++++++++++-- 6 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 test/elevation.c diff --git a/src/win/error.c b/src/win/error.c index c512f35af97..642d1112e11 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 00000000000..87d1b912963 --- /dev/null +++ b/test/elevation.c @@ -0,0 +1,23 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +int main(int argc, char **argv) { + return 0; +} diff --git a/test/test-error.c b/test/test-error.c index 4c4efa30cdd..ff53eb1d777 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 be3f9069cc7..dce8d0aa24f 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 53a036969b6..df4549bb291 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -215,6 +215,54 @@ TEST_IMPL(spawn_fails_check_for_waitpid_cleanup) { #endif +#ifdef _WIN32 +TEST_IMPL(spawn_requires_elevation) { + int r; + uv_fs_t req; + uv_loop_t* loop = uv_default_loop(); + 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); + 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)); + + uv_fs_req_cleanup(&req); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif + + TEST_IMPL(spawn_exit_code) { int r; diff --git a/uv.gyp b/uv.gyp index b969a8cd5da..bf1143ff049 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', + } + }, + } + ], + }], + ], }