Blob Blame History Raw
/*********************************************************/
/*  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;
}