diff options
Diffstat (limited to 'src/pty')
-rw-r--r-- | src/pty/ptyc_spawn.c | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/src/pty/ptyc_spawn.c b/src/pty/ptyc_spawn.c new file mode 100644 index 0000000..93b8237 --- /dev/null +++ b/src/pty/ptyc_spawn.c @@ -0,0 +1,262 @@ +/*********************************************************/ +/* ptycon: a pty-console bridge */ +/* Copyright (C) 2016 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.PTYCON. */ +/*********************************************************/ + +#include <psxtypes/psxtypes.h> +#include <ntcon/ntcon.h> +#include <ntapi/ntapi.h> + +#include <ptycon/ptycon.h> +#include "ptycon_driver_impl.h" + +static int32_t __stdcall ptyc_spawn_return( + nt_runtime_data_block * rtblock, + int32_t status) +{ + nt_runtime_data * rtdata; + + rtdata = (nt_runtime_data *)rtblock; + + if (rtdata->hready) + ntapi->zw_close( + rtdata->hready); + + ntapi->zw_free_virtual_memory( + NT_CURRENT_PROCESS_HANDLE, + &rtblock->addr, + &rtblock->size, + NT_MEM_RELEASE); + + return status; +} + +int __stdcall ptyc_spawn(struct ptyc_driver_ctx * dctx) +{ + int32_t status; + char * patharg; + void * hchild[2]; + nt_create_process_params params; + struct ptyc_driver_ctx_impl * ictx; + struct ptyc_client_ctx * clctx; + nt_tty_session_info session; + nt_runtime_data_block rtblock; + nt_runtime_data * rdata; + nt_rtdata * self; + nt_peb * peb; + void * hat; + void * hfile; + char ** rargv; + char ** renvp; + wchar16_t ** pwarg; + wchar16_t * wch; + nt_unicode_string * imgname; + uint32_t written; + uintptr_t imgbuf[8192/sizeof(uintptr_t)]; + + /* init */ + if (!(ictx = ptyc_get_driver_ictx(dctx))) + return NT_STATUS_INVALID_HANDLE; + + if (!dctx->cctx->eargv) + return NT_STATUS_SUCCESS; + + if ((status = ntapi->tt_get_runtime_data(&self,0))) + return status; + + clctx = &ictx->clctx; + + /* hat */ + if (!(peb = (nt_peb *)pe_get_peb_address())) + return NT_STATUS_INTERNAL_ERROR; + + if (!peb->process_params) + return NT_STATUS_INTERNAL_ERROR; + + hat = (dctx->cctx->hroot && (dctx->cctx->eargv[0][0] == '/')) + ? dctx->cctx->hroot + : self->hcwd + ? self->hcwd + : peb->process_params->cwd_handle; + + patharg = (dctx->cctx->eargv[0][0] == '/') + ? &dctx->cctx->eargv[0][1] + : &dctx->cctx->eargv[0][0]; + + /* hfile */ + if ((status = ptyc_open_file(&hfile,hat,patharg,true))) + return status; + + /* rtblock */ + rtblock.addr = 0; + rtblock.size = 0x10000; + rtblock.remote_addr = 0; + rtblock.remote_size = 0; + rtblock.flags = 0; + + if ((status = ntapi->zw_allocate_virtual_memory( + self->hprocess_self, + &rtblock.addr,0, + &rtblock.size, + NT_MEM_COMMIT, + NT_PAGE_READWRITE))) + return status; + + ntapi->tt_aligned_block_memset( + rtblock.addr,0,rtblock.size); + + if ((status = ntapi->zw_query_object( + hfile, + NT_OBJECT_NAME_INFORMATION, + imgbuf,sizeof(imgbuf), + &written))) + return ptyc_spawn_return( + &rtblock,status); + + imgname = (nt_unicode_string *)imgbuf; + rdata = (nt_runtime_data *)rtblock.addr; + + /* argv, envp */ + if ((status = ntapi->tt_array_copy_utf8( + &rdata->argc, + (const char **)dctx->cctx->eargv, + (const char **)self->envp, + 0,0,0, + rtblock.addr, + rdata->buffer, + rtblock.size - sizeof(*rdata), + &rtblock.remote_size))) + return ptyc_spawn_return( + &rtblock,status); + + rdata->argv = (char **)&((nt_runtime_data *)0)->buffer; + rdata->envp = rdata->argv + rdata->argc + 1; + + rdata->wargv = (wchar16_t **)(rdata->buffer + (rtblock.remote_size / sizeof(uintptr_t)) + 1); + rdata->wenvp = rdata->wargv + rdata->argc + 1; + + rargv = rdata->argv + ((uintptr_t)rtblock.addr / sizeof(char *)); + renvp = rdata->envp + ((uintptr_t)rtblock.addr / sizeof(char *)); + + pwarg = rdata->wenvp + self->envc + 1; + wch = (wchar16_t *)pwarg; + + if ((status = ntapi->tt_array_convert_utf8_to_utf16( + rargv, + rdata->wargv, + rdata, + wch, + rtblock.size - sizeof(wchar16_t)*(wch-(wchar16_t *)rdata->buffer), + &rtblock.remote_size))) + return ptyc_spawn_return( + &rtblock,status); + + wch += rtblock.remote_size/sizeof(wchar16_t); + + if ((status = ntapi->tt_array_convert_utf8_to_utf16( + renvp, + rdata->wenvp, + rdata, + wch, + rtblock.size - sizeof(wchar16_t)*(wch-(wchar16_t *)rdata->buffer), + &rtblock.remote_size))) + return ptyc_spawn_return( + &rtblock,status); + + rdata->wargv -= (uintptr_t)rtblock.addr / sizeof(wchar16_t *); + rdata->wenvp -= (uintptr_t)rtblock.addr / sizeof(wchar16_t *); + + /* session */ + if ((status = ntapi->tt_create_inheritable_event( + &rdata->hready, + NT_NOTIFICATION_EVENT, + NT_EVENT_NOT_SIGNALED))) + return ptyc_spawn_return( + &rtblock,status); + + ntapi->tt_aligned_block_memcpy( + (uintptr_t *)&rdata->cid_parent, + (uintptr_t *)&self->cid_self, + sizeof(nt_cid)); + + rdata->hroot = dctx->cctx->hroot; + rdata->hcwd = self->hcwd + ? self->hcwd + : peb->process_params->cwd_handle; + + rdata->srv_keys[0] = self->srv_keys[0]; + rdata->srv_keys[1] = self->srv_keys[1]; + rdata->srv_keys[2] = self->srv_keys[2]; + rdata->srv_keys[3] = self->srv_keys[3]; + rdata->srv_keys[4] = self->srv_keys[4]; + rdata->srv_keys[5] = self->srv_keys[5]; + + rdata->hstdin = NT_INVALID_HANDLE_VALUE; + rdata->hstdout = NT_INVALID_HANDLE_VALUE; + rdata->hstderr = NT_INVALID_HANDLE_VALUE; + + rdata->stdin_type = NT_FILE_TYPE_PTY; + rdata->stdout_type = NT_FILE_TYPE_PTY; + rdata->stderr_type = NT_FILE_TYPE_PTY; + + rdata->ptyany[0] = clctx->clinfo.any[0]; + rdata->ptyany[1] = clctx->clinfo.any[1]; + rdata->ptyany[2] = clctx->clinfo.any[2]; + rdata->ptyany[3] = clctx->clinfo.any[3]; + + /* params */ + ntapi->tt_aligned_block_memset( + ¶ms,0,sizeof(params)); + + params.image_name = imgname->buffer; + params.rtblock = &rtblock; + params.creation_flags_process = NT_PROCESS_CREATE_FLAGS_INHERIT_HANDLES; + params.creation_flags_thread = NT_PROCESS_CREATE_FLAGS_CREATE_THREAD_SUSPENDED; + + /* hoppla */ + if ((status = ntapi->tt_create_native_process(¶ms))) + return ptyc_spawn_return( + &rtblock,status); + + /* clctx */ + clctx->hprocess = params.hprocess; + clctx->hthread = params.hthread; + clctx->cid.process_id = params.cid.process_id; + clctx->cid.thread_id = params.cid.thread_id; + + if ((status = ntapi->tty_client_process_register( + self->hsession, + params.pbi.unique_process_id, + 0,NT_TTY_INHERIT_HANDLES,0))) + ntapi->zw_terminate_process( + params.hprocess, + status); + + session.pid = 0; + session.pgid = 0; + session.sid = 0; + session.syspid = params.pbi.unique_process_id; + + if ((status = ntapi->tty_client_session_set(0,&session))) + ntapi->zw_terminate_process( + params.hprocess, + status); + + if ((status = ntapi->zw_resume_thread(params.hthread,0))) + ntapi->zw_terminate_process( + params.hprocess, + status); + + hchild[1] = params.hprocess; + hchild[0] = rdata->hready; + + ntapi->zw_wait_for_multiple_objects( + 2,hchild, + NT_WAIT_ANY, + NT_SYNC_NON_ALERTABLE, + 0); + + return ptyc_spawn_return( + &rtblock,status); +} |