/*********************************************************/
/* ptycon: a pty-console bridge */
/* Copyright (C) 2016--2017 SysDeer Technologies, LLC */
/* Released under GPLv2 and GPLv3; see COPYING.PTYCON. */
/*********************************************************/
#include <psxtypes/psxtypes.h>
#include <ntapi/ntapi.h>
#include <ptycon/ptycon.h>
#include "ptycon_daemon_impl.h"
#include "ptycon_driver_impl.h"
#define PTYC_VTBL_ELEMENTS PTYC_DAEMON_OPCODE_CAP - PTYC_DAEMON_OPCODE_BASE
static ptyc_daemon_routine * ptyc_daemon_vtbl[PTYC_VTBL_ELEMENTS] = {
ptyc_daemon_connect,
0,
ptyc_daemon_signal,
0,
0,
0
};
static int ptyc_init_pidmap_target_symlink(struct ptyc_daemon_ctx * dctx)
{
int status;
void * hkeydir;
struct ptyc_driver_ctx_impl * ictx = ptyc_get_driver_ictx(dctx->driver_ctx);
if ((status = ntapi->tt_create_keyed_object_directory(
&hkeydir,
NT_SYMBOLIC_LINK_ALL_ACCESS,
ictx->rtdata->hpidmapdir,
pe_get_current_process_id())))
return status;
if ((status = ntapi->zw_set_information_object(
hkeydir,
NT_OBJECT_HANDLE_INFORMATION,
&(nt_object_handle_information){0,0},
sizeof(nt_object_handle_information))))
return status;
return ntapi->tt_create_keyed_object_directory_entry(
&ictx->hntpipc,
NT_SYMBOLIC_LINK_ALL_ACCESS,
hkeydir,
dctx->hport_daemon,0,
pe_get_current_process_id());
}
static int ptyc_init_ntpipc_target_symlink(struct ptyc_daemon_ctx * dctx)
{
struct ptyc_driver_ctx_impl * ictx = ptyc_get_driver_ictx(dctx->driver_ctx);
return ntapi->tt_create_keyed_object_directory_entry(
&ictx->hntpipc,
NT_SYMBOLIC_LINK_ALL_ACCESS,
ictx->rtdata->hntpipcdir,
dctx->hport_daemon,0,
pe_get_current_process_id());
}
int32_t __stdcall ptyc_daemon_loop(void * ctx)
{
int status;
struct ptyc_daemon_ctx * dctx;
nt_rtdata * rtdata;
nt_tty_port_msg inbuf;
nt_tty_port_msg outbuf;
nt_tty_port_msg * request;
nt_tty_port_msg * reply;
intptr_t port_id;
int32_t opcode;
if (ntapi->tt_get_runtime_data(&rtdata,0))
return NT_STATUS_INTERNAL_ERROR;
dctx = (struct ptyc_daemon_ctx *)ctx;
/* pidmap daemon symlink */
if ((status = ptyc_init_pidmap_target_symlink(dctx)))
return status;
/* ntpipc daemon symlink */
if ((status = ptyc_init_ntpipc_target_symlink(dctx)))
return status;
/* init */
request = &inbuf;
ntapi->tt_aligned_block_memset(
request,0,sizeof(*request));
/* get first message */
ntapi->zw_reply_wait_receive_port(
dctx->hport_daemon,
&port_id,
0,(nt_port_message *)request);
/* message loop */
do {
switch (request->header.msg_type) {
case NT_LPC_REQUEST:
case NT_LPC_DATAGRAM:
opcode = request->ttyinfo.opcode;
break;
case NT_LPC_CONNECTION_REQUEST:
opcode = PTYC_DAEMON_CONNECT;
break;
default:
opcode = -1;
break;
}
/* dispatch */
reply = &outbuf;
ntapi->tt_aligned_block_memcpy(
(uintptr_t *)reply,
(uintptr_t *)request,
sizeof(*reply));
reply->header.msg_type = NT_LPC_REPLY;
if ((opcode >= PTYC_DAEMON_OPCODE_BASE) && (opcode < PTYC_DAEMON_OPCODE_CAP)) {
reply->ttyinfo.exarg = (void *)request->header.client_id.process_id;
opcode -= PTYC_DAEMON_OPCODE_BASE;
if (ptyc_daemon_vtbl[opcode])
reply->ttyinfo.status = ptyc_daemon_vtbl[opcode](reply);
else
reply->ttyinfo.status = NT_STATUS_NOT_IMPLEMENTED;
} else {
reply->ttyinfo.exarg = NT_INVALID_HANDLE_VALUE;
reply->ttyinfo.status = NT_STATUS_LPC_INVALID_CONNECTION_USAGE;
}
ntapi->tt_aligned_block_memset(
request,0,sizeof(*request));
reply = reply->ttyinfo.exarg
? &outbuf : 0;
if (!reply)
ntapi->zw_reply_wait_receive_port(
dctx->hport_daemon,
&port_id,
0,&request->header);
else if (reply->header.client_id.process_id == rtdata->cid_self.process_id)
ntapi->zw_reply_wait_receive_port(
dctx->hport_daemon,
&port_id,
&reply->header,
&request->header);
else {
ntapi->zw_reply_port(
dctx->hport_daemon,
&reply->header);
ntapi->zw_reply_wait_receive_port(
dctx->hport_daemon,
&port_id,
0,&request->header);
}
} while (request->header.msg_id);
return NT_STATUS_INTERNAL_ERROR;
}