pipe: allow access from other users
Adds new uv_pipe_chmod function which can be used to make the pipe writable or readable by all users. PR-URL: https://github.com/libuv/libuv/pull/1386 Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
This commit is contained in:
parent
96ea5ac96d
commit
fd02ab681b
@ -212,6 +212,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
|
|||||||
test/test-pipe-server-close.c \
|
test/test-pipe-server-close.c \
|
||||||
test/test-pipe-close-stdout-read-stdin.c \
|
test/test-pipe-close-stdout-read-stdin.c \
|
||||||
test/test-pipe-set-non-blocking.c \
|
test/test-pipe-set-non-blocking.c \
|
||||||
|
test/test-pipe-set-fchmod.c \
|
||||||
test/test-platform-output.c \
|
test/test-platform-output.c \
|
||||||
test/test-poll.c \
|
test/test-poll.c \
|
||||||
test/test-poll-close.c \
|
test/test-poll-close.c \
|
||||||
|
|||||||
@ -102,3 +102,12 @@ API
|
|||||||
and call ``uv_accept(pipe, handle)``.
|
and call ``uv_accept(pipe, handle)``.
|
||||||
|
|
||||||
.. seealso:: The :c:type:`uv_stream_t` API functions also apply.
|
.. seealso:: The :c:type:`uv_stream_t` API functions also apply.
|
||||||
|
|
||||||
|
.. c:function:: int uv_pipe_chmod(uv_pipe_t* handle, int flags)
|
||||||
|
|
||||||
|
Alters pipe permissions, allowing it to be accessed from processes run by
|
||||||
|
different users. Makes the pipe writable or readable by all users. Mode can
|
||||||
|
be ``UV_WRITABLE``, ``UV_READABLE`` or ``UV_WRITABLE | UV_READABLE``. This
|
||||||
|
function is blocking.
|
||||||
|
|
||||||
|
.. versionadded:: 1.16.0
|
||||||
|
|||||||
@ -710,6 +710,7 @@ UV_EXTERN int uv_pipe_getpeername(const uv_pipe_t* handle,
|
|||||||
UV_EXTERN void uv_pipe_pending_instances(uv_pipe_t* handle, int count);
|
UV_EXTERN void uv_pipe_pending_instances(uv_pipe_t* handle, int count);
|
||||||
UV_EXTERN int uv_pipe_pending_count(uv_pipe_t* handle);
|
UV_EXTERN int uv_pipe_pending_count(uv_pipe_t* handle);
|
||||||
UV_EXTERN uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle);
|
UV_EXTERN uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle);
|
||||||
|
UV_EXTERN int uv_pipe_chmod(uv_pipe_t* handle, int flags);
|
||||||
|
|
||||||
|
|
||||||
struct uv_poll_s {
|
struct uv_poll_s {
|
||||||
|
|||||||
@ -302,3 +302,56 @@ uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
|
|||||||
else
|
else
|
||||||
return uv__handle_type(handle->accepted_fd);
|
return uv__handle_type(handle->accepted_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
|
||||||
|
unsigned desired_mode;
|
||||||
|
struct stat pipe_stat;
|
||||||
|
char* name_buffer;
|
||||||
|
size_t name_len;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (handle == NULL || uv__stream_fd(handle) == -1)
|
||||||
|
return -EBADF;
|
||||||
|
|
||||||
|
if (mode != UV_READABLE &&
|
||||||
|
mode != UV_WRITABLE &&
|
||||||
|
mode != (UV_WRITABLE | UV_READABLE))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (fstat(uv__stream_fd(handle), &pipe_stat) == -1)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
desired_mode = 0;
|
||||||
|
if (mode & UV_READABLE)
|
||||||
|
desired_mode |= S_IRUSR | S_IRGRP | S_IROTH;
|
||||||
|
if (mode & UV_WRITABLE)
|
||||||
|
desired_mode |= S_IWUSR | S_IWGRP | S_IWOTH;
|
||||||
|
|
||||||
|
/* Exit early if pipe already has desired mode. */
|
||||||
|
if ((pipe_stat.st_mode & desired_mode) == desired_mode)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
pipe_stat.st_mode |= desired_mode;
|
||||||
|
|
||||||
|
/* Unfortunately fchmod does not work on all platforms, we will use chmod. */
|
||||||
|
name_len = 0;
|
||||||
|
r = uv_pipe_getsockname(handle, NULL, &name_len);
|
||||||
|
if (r != UV_ENOBUFS)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
name_buffer = uv__malloc(name_len);
|
||||||
|
if (name_buffer == NULL)
|
||||||
|
return UV_ENOMEM;
|
||||||
|
|
||||||
|
r = uv_pipe_getsockname(handle, name_buffer, &name_len);
|
||||||
|
if (r != 0) {
|
||||||
|
uv__free(name_buffer);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = chmod(name_buffer, pipe_stat.st_mode);
|
||||||
|
uv__free(name_buffer);
|
||||||
|
|
||||||
|
return r != -1 ? 0 : -errno;
|
||||||
|
}
|
||||||
|
|||||||
@ -31,6 +31,9 @@
|
|||||||
#include "stream-inl.h"
|
#include "stream-inl.h"
|
||||||
#include "req-inl.h"
|
#include "req-inl.h"
|
||||||
|
|
||||||
|
#include <AclAPI.h>
|
||||||
|
#include <AccCtrl.h>
|
||||||
|
|
||||||
typedef struct uv__ipc_queue_item_s uv__ipc_queue_item_t;
|
typedef struct uv__ipc_queue_item_s uv__ipc_queue_item_t;
|
||||||
|
|
||||||
struct uv__ipc_queue_item_s {
|
struct uv__ipc_queue_item_s {
|
||||||
@ -202,7 +205,7 @@ int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
|
|||||||
uv_unique_pipe_name(ptr, name, nameSize);
|
uv_unique_pipe_name(ptr, name, nameSize);
|
||||||
|
|
||||||
pipeHandle = CreateNamedPipeA(name,
|
pipeHandle = CreateNamedPipeA(name,
|
||||||
access | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE,
|
access | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE | WRITE_DAC,
|
||||||
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 65536, 65536, 0,
|
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 65536, 65536, 0,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
@ -534,7 +537,7 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
|
|||||||
*/
|
*/
|
||||||
handle->pipe.serv.accept_reqs[0].pipeHandle = CreateNamedPipeW(handle->name,
|
handle->pipe.serv.accept_reqs[0].pipeHandle = CreateNamedPipeW(handle->name,
|
||||||
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
|
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
|
||||||
FILE_FLAG_FIRST_PIPE_INSTANCE,
|
FILE_FLAG_FIRST_PIPE_INSTANCE | WRITE_DAC,
|
||||||
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
|
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
|
||||||
PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
|
PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
|
||||||
|
|
||||||
@ -803,7 +806,7 @@ static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle,
|
|||||||
assert(req->pipeHandle == INVALID_HANDLE_VALUE);
|
assert(req->pipeHandle == INVALID_HANDLE_VALUE);
|
||||||
|
|
||||||
req->pipeHandle = CreateNamedPipeW(handle->name,
|
req->pipeHandle = CreateNamedPipeW(handle->name,
|
||||||
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
|
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | WRITE_DAC,
|
||||||
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
|
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
|
||||||
PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
|
PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
|
||||||
|
|
||||||
@ -2132,3 +2135,80 @@ uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
|
|||||||
else
|
else
|
||||||
return UV_TCP;
|
return UV_TCP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
|
||||||
|
SID_IDENTIFIER_AUTHORITY sid_world = SECURITY_WORLD_SID_AUTHORITY;
|
||||||
|
PACL old_dacl, new_dacl;
|
||||||
|
PSECURITY_DESCRIPTOR sd;
|
||||||
|
EXPLICIT_ACCESS ea;
|
||||||
|
PSID everyone;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if (handle == NULL || handle->handle == INVALID_HANDLE_VALUE)
|
||||||
|
return UV_EBADF;
|
||||||
|
|
||||||
|
if (mode != UV_READABLE &&
|
||||||
|
mode != UV_WRITABLE &&
|
||||||
|
mode != (UV_WRITABLE | UV_READABLE))
|
||||||
|
return UV_EINVAL;
|
||||||
|
|
||||||
|
if (!AllocateAndInitializeSid(&sid_world,
|
||||||
|
1,
|
||||||
|
SECURITY_WORLD_RID,
|
||||||
|
0, 0, 0, 0, 0, 0, 0,
|
||||||
|
&everyone)) {
|
||||||
|
error = GetLastError();
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetSecurityInfo(handle->handle,
|
||||||
|
SE_KERNEL_OBJECT,
|
||||||
|
DACL_SECURITY_INFORMATION,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&old_dacl,
|
||||||
|
NULL,
|
||||||
|
&sd)) {
|
||||||
|
error = GetLastError();
|
||||||
|
goto clean_sid;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&ea, 0, sizeof(EXPLICIT_ACCESS));
|
||||||
|
if (mode & UV_READABLE)
|
||||||
|
ea.grfAccessPermissions |= GENERIC_READ | FILE_WRITE_ATTRIBUTES;
|
||||||
|
if (mode & UV_WRITABLE)
|
||||||
|
ea.grfAccessPermissions |= GENERIC_WRITE | FILE_READ_ATTRIBUTES;
|
||||||
|
ea.grfAccessPermissions |= SYNCHRONIZE;
|
||||||
|
ea.grfAccessMode = SET_ACCESS;
|
||||||
|
ea.grfInheritance = NO_INHERITANCE;
|
||||||
|
ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
|
||||||
|
ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
|
||||||
|
ea.Trustee.ptstrName = (LPTSTR)everyone;
|
||||||
|
|
||||||
|
if (SetEntriesInAcl(1, &ea, old_dacl, &new_dacl)) {
|
||||||
|
error = GetLastError();
|
||||||
|
goto clean_sd;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SetSecurityInfo(handle->handle,
|
||||||
|
SE_KERNEL_OBJECT,
|
||||||
|
DACL_SECURITY_INFORMATION,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
new_dacl,
|
||||||
|
NULL)) {
|
||||||
|
error = GetLastError();
|
||||||
|
goto clean_dacl;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = 0;
|
||||||
|
|
||||||
|
clean_dacl:
|
||||||
|
LocalFree((HLOCAL) new_dacl);
|
||||||
|
clean_sd:
|
||||||
|
LocalFree((HLOCAL) sd);
|
||||||
|
clean_sid:
|
||||||
|
FreeSid(everyone);
|
||||||
|
done:
|
||||||
|
return uv_translate_sys_error(error);
|
||||||
|
}
|
||||||
|
|||||||
@ -204,6 +204,7 @@ TEST_DECLARE (pipe_ref4)
|
|||||||
TEST_DECLARE (pipe_close_stdout_read_stdin)
|
TEST_DECLARE (pipe_close_stdout_read_stdin)
|
||||||
#endif
|
#endif
|
||||||
TEST_DECLARE (pipe_set_non_blocking)
|
TEST_DECLARE (pipe_set_non_blocking)
|
||||||
|
TEST_DECLARE (pipe_set_chmod)
|
||||||
TEST_DECLARE (process_ref)
|
TEST_DECLARE (process_ref)
|
||||||
TEST_DECLARE (has_ref)
|
TEST_DECLARE (has_ref)
|
||||||
TEST_DECLARE (active)
|
TEST_DECLARE (active)
|
||||||
@ -443,6 +444,7 @@ TASK_LIST_START
|
|||||||
TEST_ENTRY (pipe_close_stdout_read_stdin)
|
TEST_ENTRY (pipe_close_stdout_read_stdin)
|
||||||
#endif
|
#endif
|
||||||
TEST_ENTRY (pipe_set_non_blocking)
|
TEST_ENTRY (pipe_set_non_blocking)
|
||||||
|
TEST_ENTRY (pipe_set_chmod)
|
||||||
TEST_ENTRY (tty)
|
TEST_ENTRY (tty)
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
TEST_ENTRY (tty_raw)
|
TEST_ENTRY (tty_raw)
|
||||||
|
|||||||
66
test/test-pipe-set-fchmod.c
Normal file
66
test/test-pipe-set-fchmod.c
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/* Copyright libuv project 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 "uv.h"
|
||||||
|
#include "task.h"
|
||||||
|
|
||||||
|
TEST_IMPL(pipe_set_chmod) {
|
||||||
|
uv_pipe_t pipe_handle;
|
||||||
|
uv_loop_t* loop;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
loop = uv_default_loop();
|
||||||
|
|
||||||
|
r = uv_pipe_init(loop, &pipe_handle, 0);
|
||||||
|
ASSERT(r == 0);
|
||||||
|
|
||||||
|
r = uv_pipe_bind(&pipe_handle, TEST_PIPENAME);
|
||||||
|
ASSERT(r == 0);
|
||||||
|
|
||||||
|
/* No easy way to test if this works, we will only make sure that */
|
||||||
|
/* the call is successful. */
|
||||||
|
r = uv_pipe_chmod(&pipe_handle, UV_READABLE);
|
||||||
|
if (r == UV_EPERM) {
|
||||||
|
MAKE_VALGRIND_HAPPY();
|
||||||
|
RETURN_SKIP("Insufficient privileges to alter pipe fmode");
|
||||||
|
}
|
||||||
|
ASSERT(r == 0);
|
||||||
|
|
||||||
|
r = uv_pipe_chmod(&pipe_handle, UV_WRITABLE);
|
||||||
|
ASSERT(r == 0);
|
||||||
|
|
||||||
|
r = uv_pipe_chmod(&pipe_handle, UV_WRITABLE | UV_READABLE);
|
||||||
|
ASSERT(r == 0);
|
||||||
|
|
||||||
|
r = uv_pipe_chmod(NULL, UV_WRITABLE | UV_READABLE);
|
||||||
|
ASSERT(r == UV_EBADF);
|
||||||
|
|
||||||
|
r = uv_pipe_chmod(&pipe_handle, 12345678);
|
||||||
|
ASSERT(r == UV_EINVAL);
|
||||||
|
|
||||||
|
uv_close((uv_handle_t*)&pipe_handle, NULL);
|
||||||
|
r = uv_pipe_chmod(&pipe_handle, UV_WRITABLE | UV_READABLE);
|
||||||
|
ASSERT(r == UV_EBADF);
|
||||||
|
|
||||||
|
MAKE_VALGRIND_HAPPY();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
1
uv.gyp
1
uv.gyp
@ -393,6 +393,7 @@
|
|||||||
'test/test-pipe-server-close.c',
|
'test/test-pipe-server-close.c',
|
||||||
'test/test-pipe-close-stdout-read-stdin.c',
|
'test/test-pipe-close-stdout-read-stdin.c',
|
||||||
'test/test-pipe-set-non-blocking.c',
|
'test/test-pipe-set-non-blocking.c',
|
||||||
|
'test/test-pipe-set-fchmod.c',
|
||||||
'test/test-platform-output.c',
|
'test/test-platform-output.c',
|
||||||
'test/test-poll.c',
|
'test/test-poll.c',
|
||||||
'test/test-poll-close.c',
|
'test/test-poll-close.c',
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user