server: Support creating processes with specified parent.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47817
Signed-off-by: Paul Gofman <gofmanp@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
stable
Paul Gofman 2019-12-12 14:18:31 +03:00 committed by Alexandre Julliard
parent b989a85484
commit 74a74556dd
11 changed files with 76 additions and 46 deletions

View File

@ -3861,14 +3861,14 @@ void test_parent_process_attribute(unsigned int level, HANDLE read_pipe)
memset(&parent_data, 0, sizeof(parent_data));
ret = ReadFile(read_pipe, &parent_data, sizeof(parent_data), &size, NULL);
todo_wine_if(level == 2) ok((level == 2 && ret) || (level == 1 && !ret && GetLastError() == ERROR_INVALID_HANDLE),
ok((level == 2 && ret) || (level == 1 && !ret && GetLastError() == ERROR_INVALID_HANDLE),
"Got unexpected ret %#x, level %u, GetLastError() %u.\n",
ret, level, GetLastError());
}
if (level == 2)
{
todo_wine ok(parent_id == parent_data.parent_id, "Got parent id %u, parent_data.parent_id %u.\n",
ok(parent_id == parent_data.parent_id, "Got parent id %u, parent_data.parent_id %u.\n",
parent_id, parent_data.parent_id);
return;
}

View File

@ -1709,6 +1709,7 @@ NTSTATUS WINAPI RtlCreateUserProcess( UNICODE_STRING *path, ULONG attributes,
SERVER_START_REQ( new_process )
{
req->parent_process = wine_server_obj_handle(parent);
req->inherit_all = inherit;
req->create_flags = params->DebugFlags; /* hack: creation flags stored in DebugFlags for now */
req->socket_fd = socketfd[1];

View File

@ -769,6 +769,7 @@ struct rawinput_device
struct new_process_request
{
struct request_header __header;
obj_handle_t parent_process;
int inherit_all;
unsigned int create_flags;
int socket_fd;
@ -779,6 +780,7 @@ struct new_process_request
/* VARARG(objattr,object_attributes); */
/* VARARG(info,startup_info,info_size); */
/* VARARG(env,unicode_str); */
char __pad_44[4];
};
struct new_process_reply
{
@ -6702,6 +6704,6 @@ union generic_reply
struct resume_process_reply resume_process_reply;
};
#define SERVER_PROTOCOL_VERSION 594
#define SERVER_PROTOCOL_VERSION 595
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */

View File

@ -504,37 +504,37 @@ int free_console( struct process *process )
* 2/ parent is a renderer which launches process, and process should attach to the console
* rendered by parent
*/
void inherit_console(struct thread *parent_thread, struct process *process, obj_handle_t hconin)
void inherit_console( struct thread *parent_thread, struct process *parent, struct process *process,
obj_handle_t hconin )
{
int done = 0;
struct process* parent = parent_thread->process;
/* if parent is a renderer, then attach current process to its console
* a bit hacky....
*/
if (hconin)
if (hconin && parent_thread)
{
struct console_input* console;
struct console_input *console;
/* FIXME: should we check some access rights ? */
if ((console = (struct console_input*)get_handle_obj( parent, hconin,
0, &console_input_ops )))
{
if ((console = (struct console_input *)get_handle_obj( parent, hconin,
0, &console_input_ops )))
{
if (console->renderer == parent_thread)
{
process->console = (struct console_input*)grab_object( console );
process->console->num_proc++;
done = 1;
}
release_object( console );
}
{
process->console = (struct console_input *)grab_object( console );
process->console->num_proc++;
done = 1;
}
release_object( console );
}
else clear_error(); /* ignore error */
}
/* otherwise, if parent has a console, attach child to this console */
if (!done && parent->console)
{
process->console = (struct console_input*)grab_object( parent->console );
process->console->num_proc++;
process->console = (struct console_input *)grab_object( parent->console );
process->console->num_proc++;
}
}

View File

@ -1116,7 +1116,8 @@ DECL_HANDLER(new_process)
const struct security_descriptor *sd;
const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, NULL );
struct process *process = NULL;
struct process *parent = current->process;
struct process *parent;
struct thread *parent_thread = current;
int socket_fd = thread_get_inflight_fd( current, req->socket_fd );
if (socket_fd == -1)
@ -1148,11 +1149,23 @@ DECL_HANDLER(new_process)
return;
}
if (req->parent_process)
{
if (!(parent = get_process_from_handle( req->parent_process, PROCESS_CREATE_PROCESS)))
{
close( socket_fd );
return;
}
parent_thread = NULL;
}
else parent = (struct process *)grab_object( current->process );
if (parent->job && (req->create_flags & CREATE_BREAKAWAY_FROM_JOB) &&
!(parent->job->limit_flags & (JOB_OBJECT_LIMIT_BREAKAWAY_OK | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK)))
{
set_error( STATUS_ACCESS_DENIED );
close( socket_fd );
release_object( parent );
return;
}
@ -1160,6 +1173,7 @@ DECL_HANDLER(new_process)
if (!(info = alloc_object( &startup_info_ops )))
{
close( socket_fd );
release_object( parent );
return;
}
info->process = NULL;
@ -1222,7 +1236,7 @@ DECL_HANDLER(new_process)
}
/* connect to the window station */
connect_process_winstation( process, current );
connect_process_winstation( process, parent_thread, parent );
/* set the process console */
if (!(req->create_flags & (DETACHED_PROCESS | CREATE_NEW_CONSOLE)))
@ -1231,7 +1245,7 @@ DECL_HANDLER(new_process)
* like if hConOut and hConIn are console handles, then they should be on the same
* physical console
*/
inherit_console( current, process, req->inherit_all ? info->data->hstdin : 0 );
inherit_console( parent_thread, parent, process, req->inherit_all ? info->data->hstdin : 0 );
}
if (!req->inherit_all && !(req->create_flags & CREATE_NEW_CONSOLE))
@ -1246,16 +1260,15 @@ DECL_HANDLER(new_process)
if (get_error() == STATUS_INVALID_HANDLE ||
get_error() == STATUS_OBJECT_TYPE_MISMATCH) clear_error();
}
/* attach to the debugger if requested */
if (req->create_flags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS))
{
set_process_debugger( process, current );
process->debug_children = !(req->create_flags & DEBUG_ONLY_THIS_PROCESS);
}
else if (parent->debugger && parent->debug_children)
else if (current->process->debugger && current->process->debug_children)
{
set_process_debugger( process, parent->debugger );
set_process_debugger( process, current->process->debugger );
/* debug_children is set to 1 by default */
}
@ -1265,10 +1278,11 @@ DECL_HANDLER(new_process)
info->process = (struct process *)grab_object( process );
reply->info = alloc_handle( current->process, info, SYNCHRONIZE, 0 );
reply->pid = get_process_id( process );
reply->handle = alloc_handle_no_access_check( parent, process, req->access, objattr->attributes );
reply->handle = alloc_handle_no_access_check( current->process, process, req->access, objattr->attributes );
done:
if (process) release_object( process );
release_object( parent );
release_object( info );
}

View File

@ -141,7 +141,8 @@ extern struct process_snapshot *process_snap( int *count );
extern void enum_processes( int (*cb)(struct process*, void*), void *user);
/* console functions */
extern void inherit_console(struct thread *parent_thread, struct process *process, obj_handle_t hconin);
extern void inherit_console( struct thread *parent_thread, struct process *parent,
struct process *process, obj_handle_t hconin );
extern int free_console( struct process *process );
extern struct thread *console_get_renderer( struct console_input *console );

View File

@ -783,6 +783,7 @@ struct rawinput_device
/* Create a new process from the context of the parent */
@REQ(new_process)
obj_handle_t parent_process; /* parent process */
int inherit_all; /* inherit all handles from parent */
unsigned int create_flags; /* creation flags */
int socket_fd; /* file descriptor for process socket */

View File

@ -745,14 +745,15 @@ C_ASSERT( sizeof(unsigned char) == 1 );
C_ASSERT( sizeof(unsigned int) == 4 );
C_ASSERT( sizeof(unsigned short) == 2 );
C_ASSERT( sizeof(user_handle_t) == 4 );
C_ASSERT( FIELD_OFFSET(struct new_process_request, inherit_all) == 12 );
C_ASSERT( FIELD_OFFSET(struct new_process_request, create_flags) == 16 );
C_ASSERT( FIELD_OFFSET(struct new_process_request, socket_fd) == 20 );
C_ASSERT( FIELD_OFFSET(struct new_process_request, exe_file) == 24 );
C_ASSERT( FIELD_OFFSET(struct new_process_request, access) == 28 );
C_ASSERT( FIELD_OFFSET(struct new_process_request, cpu) == 32 );
C_ASSERT( FIELD_OFFSET(struct new_process_request, info_size) == 36 );
C_ASSERT( sizeof(struct new_process_request) == 40 );
C_ASSERT( FIELD_OFFSET(struct new_process_request, parent_process) == 12 );
C_ASSERT( FIELD_OFFSET(struct new_process_request, inherit_all) == 16 );
C_ASSERT( FIELD_OFFSET(struct new_process_request, create_flags) == 20 );
C_ASSERT( FIELD_OFFSET(struct new_process_request, socket_fd) == 24 );
C_ASSERT( FIELD_OFFSET(struct new_process_request, exe_file) == 28 );
C_ASSERT( FIELD_OFFSET(struct new_process_request, access) == 32 );
C_ASSERT( FIELD_OFFSET(struct new_process_request, cpu) == 36 );
C_ASSERT( FIELD_OFFSET(struct new_process_request, info_size) == 40 );
C_ASSERT( sizeof(struct new_process_request) == 48 );
C_ASSERT( FIELD_OFFSET(struct new_process_reply, info) == 8 );
C_ASSERT( FIELD_OFFSET(struct new_process_reply, pid) == 12 );
C_ASSERT( FIELD_OFFSET(struct new_process_reply, handle) == 16 );

View File

@ -1243,7 +1243,8 @@ typedef void (*dump_func)( const void *req );
static void dump_new_process_request( const struct new_process_request *req )
{
fprintf( stderr, " inherit_all=%d", req->inherit_all );
fprintf( stderr, " parent_process=%04x", req->parent_process );
fprintf( stderr, ", inherit_all=%d", req->inherit_all );
fprintf( stderr, ", create_flags=%08x", req->create_flags );
fprintf( stderr, ", socket_fd=%d", req->socket_fd );
fprintf( stderr, ", exe_file=%04x", req->exe_file );

View File

@ -183,7 +183,8 @@ extern client_ptr_t get_class_client_ptr( struct window_class *class );
extern struct desktop *get_desktop_obj( struct process *process, obj_handle_t handle, unsigned int access );
extern struct winstation *get_process_winstation( struct process *process, unsigned int access );
extern struct desktop *get_thread_desktop( struct thread *thread, unsigned int access );
extern void connect_process_winstation( struct process *process, struct thread *parent );
extern void connect_process_winstation( struct process *process, struct thread *parent_thread,
struct process *parent_process );
extern void set_process_default_desktop( struct process *process, struct desktop *desktop,
obj_handle_t handle );
extern void close_process_desktop( struct process *process );

View File

@ -372,7 +372,8 @@ void set_process_default_desktop( struct process *process, struct desktop *deskt
}
/* connect a process to its window station */
void connect_process_winstation( struct process *process, struct thread *parent )
void connect_process_winstation( struct process *process, struct thread *parent_thread,
struct process *parent_process )
{
struct winstation *winstation = NULL;
struct desktop *desktop = NULL;
@ -383,9 +384,9 @@ void connect_process_winstation( struct process *process, struct thread *parent
{
winstation = (struct winstation *)get_handle_obj( process, handle, 0, &winstation_ops );
}
else if (parent && parent->process->winstation)
else if (parent_process->winstation)
{
handle = duplicate_handle( parent->process, parent->process->winstation,
handle = duplicate_handle( parent_process, parent_process->winstation,
process, 0, 0, DUP_HANDLE_SAME_ACCESS );
winstation = (struct winstation *)get_handle_obj( process, handle, 0, &winstation_ops );
}
@ -397,14 +398,21 @@ void connect_process_winstation( struct process *process, struct thread *parent
desktop = get_desktop_obj( process, handle, 0 );
if (!desktop || desktop->winstation != winstation) goto done;
}
else if (parent && parent->desktop)
else
{
desktop = get_desktop_obj( parent->process, parent->desktop, 0 );
if (!desktop || desktop->winstation != winstation) goto done;
handle = duplicate_handle( parent->process, parent->desktop,
process, 0, 0, DUP_HANDLE_SAME_ACCESS );
}
if (parent_thread && parent_thread->desktop)
handle = parent_thread->desktop;
else if (parent_process->desktop)
handle = parent_process->desktop;
else
goto done;
desktop = get_desktop_obj( parent_process, handle, 0 );
if (!desktop || desktop->winstation != winstation) goto done;
handle = duplicate_handle( parent_process, handle, process, 0, 0, DUP_HANDLE_SAME_ACCESS );
}
if (handle) set_process_default_desktop( process, desktop, handle );
done: