Skip to content

Commit

Permalink
win: map ERROR_ELEVATION_REQUIRED to UV_EACCES
Browse files Browse the repository at this point in the history
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: nodejs/node#9464
  • Loading branch information
richardlau committed Dec 5, 2016
1 parent 8658ef0 commit d0364db
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 2 deletions.
1 change: 1 addition & 0 deletions src/win/error.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
28 changes: 28 additions & 0 deletions test/require-elevation.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/* Copyright libuv project 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.
*/

#include <stdio.h>
#include <string.h>

int main(int argc, char **argv) {
printf("Hello world\n");
return 1;
}
1 change: 1 addition & 0 deletions test/test-error.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions test/test-list.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
76 changes: 76 additions & 0 deletions test/test-spawn.c
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,82 @@ TEST_IMPL(spawn_fails_check_for_waitpid_cleanup) {
#endif


#ifdef _WIN32
BOOL is_elevated() {
DWORD cb_size;
BOOL elevated;
TOKEN_ELEVATION elevation_token;
DWORD elevation_token_size;
HANDLE h_token;

elevated = FALSE;
h_token = NULL;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &h_token)) {
cb_size = sizeof(TOKEN_ELEVATION);
elevation_token_size = sizeof(elevation_token);
if (GetTokenInformation(h_token, TokenElevation, &elevation_token,
elevation_token_size, &cb_size)) {
elevated = elevation_token.TokenIsElevated;
}
}
if (h_token) {
CloseHandle(h_token);
}
return elevated;
}


TEST_IMPL(spawn_requires_elevation) {
int r;
uv_fs_t req;
char path[1024];

if (is_elevated()) {
RETURN_SKIP("Process is already elevated");
}

/* Find helper .exe -- Assumed to be in same location as test runner */
r = uv_exepath(exepath, &exepath_size);
ASSERT(r == 0);
exepath[exepath_size] = '\0';
snprintf(path, sizeof(path), "%s\\..\\require-elevation.exe", exepath);
r = uv_fs_realpath(uv_default_loop(), &req, path, NULL);
ASSERT(r == 0);

/*
* 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);
if (r != 0) {
printf("r == %s - %s\n", uv_err_name(r), uv_strerror(r));
}

ASSERT(r == UV_EACCES);
r = uv_is_active((uv_handle_t*) &process);
ASSERT(r == 0);
uv_close((uv_handle_t*) &process, NULL);
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
ASSERT(r == 0);

uv_fs_req_cleanup(&req);

MAKE_VALGRIND_HAPPY();
return 0;
}
#endif


TEST_IMPL(spawn_exit_code) {
int r;

Expand Down
26 changes: 24 additions & 2 deletions uv.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,6 @@
}],
]
},

{
'target_name': 'run-tests',
'type': 'executable',
Expand Down Expand Up @@ -569,5 +568,28 @@
},
},
},
]
],
'conditions': [
['OS=="win"', {
'targets': [
{
'target_name': 'require-elevation',
'type': 'executable',
'sources': [
'test/require-elevation.c'
],
'msvs_settings': {
'VCLinkerTool': {
'SubSystem': 1, # /subsystem:console
'UACExecutionLevel': 2, # requireAdministrator
'UACUIAccess': 'false',
},
'VCManifestTool': {
'EmbedManifest': 'true',
}
},
}
],
}],
],
}

0 comments on commit d0364db

Please sign in to comment.