Blame src/daemon/toks_daemon_loop.c

5e5175
/*********************************************************/
5e5175
/*  toksvc: a framework-native token broker service      */
d91fa0
/*  Copyright (C) 2020  SysDeer Technologies, LLC        */
5e5175
/*  Released under GPLv2 and GPLv3; see COPYING.TOKSVC.  */
5e5175
/*********************************************************/
5e5175
5e5175
#include <psxtypes/psxtypes.h>
5e5175
#include <ntapi/ntapi.h>
5e5175
5e5175
#include <toksvc/toksvc.h>
5e5175
#include "toksvc_daemon_impl.h"
5e5175
#include "toksvc_driver_impl.h"
f2a689
#include "toksvc_log_impl.h"
5e5175
d6a03d
#define  TOKS_VTBL_ELEMENTS   TOKS_DAEMON_OPCODE_CAP - TOKS_DAEMON_OPCODE_BASE
d6a03d
d6a03d
#define  TOKS_OPCODE_IDX(IDX) TOKS_DAEMON_ ## IDX - TOKS_DAEMON_OPCODE_BASE
d6a03d
#define  TOKS_HANDLER(IDX,fn) [TOKS_OPCODE_IDX(IDX)] = fn
d6a03d
5e5175
5e5175
static toks_daemon_routine * toks_daemon_vtbl[TOKS_VTBL_ELEMENTS] = {
d6a03d
	TOKS_HANDLER(CONNECT,       toks_daemon_connect),
d27132
	TOKS_HANDLER(CIDQUERY,      toks_daemon_cidquery),
d6a03d
	TOKS_HANDLER(TTYSIGNAL,     toks_daemon_signal),
44e933
	TOKS_HANDLER(ACQUIRE,       toks_daemon_acquire),
c78a06
	TOKS_HANDLER(RELEASE,       toks_daemon_release),
3034d1
	TOKS_HANDLER(CANCEL,        toks_daemon_cancel),
5ab1f5
	TOKS_HANDLER(ABORT,         toks_daemon_abort),
e6c547
	TOKS_HANDLER(IOCTL,         toks_daemon_ioctl),
5e5175
};
5e5175
3e9813
static toks_daemon_routine * toks_client_vtbl[TOKS_VTBL_ELEMENTS] = {
3e9813
	TOKS_HANDLER(CONNECT,       toks_daemon_connect),
d27132
	TOKS_HANDLER(CIDQUERY,      toks_daemon_cidquery),
3e9813
	TOKS_HANDLER(TTYSIGNAL,     toks_daemon_signal),
3e9813
};
3e9813
91f3f7
static const nt_guid    g_pidmap    = NT_PROCESS_GUID_PIDMAP;
91f3f7
static const wchar16_t  p_pidmap[6] = NT_PROCESS_OBJDIR_PREFIX_PIDMAP;
3187cb
91f3f7
static const nt_guid    g_ntpipc    = NT_PROCESS_GUID_NTPIPC;
91f3f7
static const wchar16_t  p_ntpipc[6] = NT_PROCESS_OBJDIR_PREFIX_NTPIPC;
3187cb
35e873
static void toks_daemon_ctrlpid_abort(struct toks_daemon_ctx * dctx)
35e873
{
35e873
	void *			hport;
35e873
	struct _nt_tty_sync_msg	msg;
35e873
35e873
	hport = dctx->hport_internal_client;
35e873
35e873
	ntapi->tt_aligned_block_memset(
35e873
		&msg,0,sizeof(msg));
35e873
35e873
	msg.header.msg_type	= NT_LPC_NEW_MESSAGE;
35e873
	msg.header.data_size	= sizeof(msg.data);
35e873
	msg.header.msg_size	= sizeof(msg);
35e873
	msg.data.ttyinfo.opcode	= TOKS_DAEMON_ABORT;
35e873
35e873
	ntapi->zw_request_wait_reply_port(
35e873
		hport,&msg,&msg;;
35e873
}
35e873
35e873
static int32_t toks_daemon_ctrlpid_wait(void * rapunzel)
35e873
{
35e873
	struct toks_daemon_ctx * dctx;
35e873
35e873
	dctx = (struct toks_daemon_ctx *)rapunzel;
35e873
35e873
	ntapi->zw_set_event(
35e873
		dctx->hswap,0);
35e873
35e873
	ntapi->zw_wait_for_single_object(
35e873
		dctx->hctrl,
35e873
		NT_SYNC_NON_ALERTABLE,
35e873
		0);
35e873
35e873
	toks_daemon_ctrlpid_abort(dctx);
35e873
35e873
	return ntapi->zw_terminate_thread(
35e873
		NT_CURRENT_THREAD_HANDLE,
35e873
		NT_STATUS_REMOTE_DISCONNECT);
35e873
35e873
}
35e873
35e873
static int32_t toks_daemon_ctrlpid_instance(struct toks_daemon_ctx * dctx)
35e873
{
35e873
	int32_t			status;
35e873
	nt_thread_params	params;
35e873
	nt_cid			cid;
35e873
	nt_oa			oa;
35e873
35e873
	if ((dctx->ctrlpid == 0) && (dctx->csyspid == 0))
35e873
		return NT_STATUS_SUCCESS;
35e873
35e873
	if (dctx->ctrlpid) {
35e873
		dctx->reqtokpid = dctx->ctrlpid;
35e873
35e873
		if ((status = toks_daemon_pidopen(dctx)))
35e873
			return status;
35e873
35e873
		dctx->csyspid = dctx->reqsyspid;
35e873
	}
35e873
35e873
	oa.len      = sizeof(oa);
35e873
	oa.root_dir = 0;
35e873
	oa.obj_name = 0;
35e873
	oa.obj_attr = 0;
35e873
	oa.sec_desc = 0;
35e873
	oa.sec_qos  = 0;
35e873
35e873
	cid.process_id = dctx->csyspid;
35e873
	cid.thread_id  = 0;
35e873
35e873
	if ((status = ntapi->zw_open_process(
35e873
			&dctx->hctrl,
35e873
			NT_PROCESS_SYNCHRONIZE,
35e873
			&oa,&cid)))
35e873
		return status;
35e873
35e873
	if ((status = ntapi->tt_create_private_event(
35e873
			&dctx->hswap,
35e873
			NT_NOTIFICATION_EVENT,
35e873
			NT_EVENT_NOT_SIGNALED)))
35e873
		return status;
35e873
35e873
	ntapi->tt_aligned_block_memset(
35e873
		&params,0,sizeof(params));
35e873
35e873
	params.hprocess		  = NT_CURRENT_PROCESS_HANDLE;
35e873
	params.start		  = toks_daemon_ctrlpid_wait;
35e873
	params.arg                = dctx;
35e873
	params.stack_size_commit  = 4 * 1024;
35e873
	params.stack_size_reserve = 4 * 1024;
35e873
	params.creation_flags	  = NT_CREATE_LOCAL_THREAD;
35e873
35e873
	if ((status = ntapi->tt_create_thread(&params))) {
35e873
		ntapi->zw_close(dctx->hctrl);
35e873
		ntapi->zw_close(dctx->hswap);
35e873
		return status;
35e873
	}
35e873
35e873
	status = ntapi->zw_wait_for_single_object(
35e873
		dctx->hswap,
35e873
		NT_SYNC_NON_ALERTABLE,
35e873
		0);
35e873
35e873
	ntapi->zw_close(dctx->hswap);
35e873
	ntapi->zw_close(params.hthread);
35e873
35e873
	if (status) {
35e873
		ntapi->zw_close(dctx->hctrl);
35e873
		return status;
35e873
	}
35e873
35e873
	return NT_STATUS_SUCCESS;
35e873
}
35e873
3187cb
static int toks_server_init_pidmap_object_directory(nt_rtdata * rtdata)
3187cb
{
3187cb
	return rtdata->hpidmapdir
3187cb
		? NT_STATUS_SUCCESS
3187cb
		: ntapi->tt_open_ipc_object_directory(
3187cb
			&rtdata->hpidmapdir,
3187cb
			NT_SEC_READ_CONTROL
3187cb
				| NT_DIRECTORY_QUERY
3187cb
				| NT_DIRECTORY_TRAVERSE
3187cb
				| NT_DIRECTORY_CREATE_OBJECT
3187cb
				| NT_DIRECTORY_CREATE_SUBDIRECTORY,
3187cb
			p_pidmap,&g_pidmap);
3187cb
}
3187cb
3187cb
static int toks_server_init_ntpipc_object_directory(nt_rtdata * rtdata)
3187cb
{
3187cb
	return rtdata->hntpipcdir
3187cb
		? NT_STATUS_SUCCESS
3187cb
		: ntapi->tt_open_ipc_object_directory(
3187cb
			&rtdata->hntpipcdir,
3187cb
			NT_SEC_READ_CONTROL
3187cb
				| NT_DIRECTORY_QUERY
3187cb
				| NT_DIRECTORY_TRAVERSE
3187cb
				| NT_DIRECTORY_CREATE_OBJECT
3187cb
				| NT_DIRECTORY_CREATE_SUBDIRECTORY,
3187cb
			p_ntpipc,&g_ntpipc);
3187cb
}
3187cb
3187cb
static int toks_init_pidmap_target_symlink(struct toks_daemon_ctx * dctx)
3187cb
{
3187cb
	int     status;
3187cb
	void *  hkeydir;
3187cb
3187cb
	struct toks_driver_ctx_impl * ictx = toks_get_driver_ictx(dctx->driver_ctx);
3187cb
3187cb
	if ((status = ntapi->tt_create_keyed_object_directory(
3187cb
			&hkeydir,
3187cb
			NT_SYMBOLIC_LINK_ALL_ACCESS,
3187cb
			ictx->rtdata->hpidmapdir,
3187cb
			pe_get_current_process_id())))
3187cb
		return status;
3187cb
3187cb
	if ((status = ntapi->zw_set_information_object(
3187cb
			hkeydir,
3187cb
			NT_OBJECT_HANDLE_INFORMATION,
3187cb
			&(nt_object_handle_information){0,0},
3187cb
			sizeof(nt_object_handle_information))))
3187cb
		return status;
3187cb
3187cb
	return ntapi->tt_create_keyed_object_directory_entry(
3187cb
		&ictx->hntpipc,
3187cb
		NT_SYMBOLIC_LINK_ALL_ACCESS,
3187cb
		hkeydir,
3187cb
		dctx->hport_daemon,0,
3187cb
		pe_get_current_process_id());
3187cb
}
3187cb
3187cb
static int toks_init_ntpipc_target_symlink(struct toks_daemon_ctx * dctx)
3187cb
{
3187cb
	struct toks_driver_ctx_impl * ictx = toks_get_driver_ictx(dctx->driver_ctx);
3187cb
3187cb
	return ntapi->tt_create_keyed_object_directory_entry(
3187cb
		&ictx->hntpipc,
3187cb
		NT_SYMBOLIC_LINK_ALL_ACCESS,
3187cb
		ictx->rtdata->hntpipcdir,
3187cb
		dctx->hport_daemon,0,
3187cb
		pe_get_current_process_id());
3187cb
}
3187cb
5e5175
int32_t __stdcall toks_daemon_loop(void * ctx)
5e5175
{
5e5175
	struct toks_daemon_ctx *	dctx;
3e9813
	toks_daemon_routine **		svcvtbl;
5e5175
	nt_rtdata *			rtdata;
5e5175
5e5175
	nt_tty_port_msg *		request;
5e5175
	nt_tty_port_msg *		reply;
5e5175
5e5175
	intptr_t			port_id;
5e5175
	int32_t				opcode;
35e873
	int32_t				status;
5e5175
8cf1b0
	/* runtime data */
5e5175
	if (ntapi->tt_get_runtime_data(&rtdata,0))
5e5175
		return NT_STATUS_INTERNAL_ERROR;
5e5175
8cf1b0
	/* daemon context and controlling (system) process */
5e5175
	dctx = (struct toks_daemon_ctx *)ctx;
5e5175
35e873
	dctx->ctrlpid = toks_get_driver_ctrlpid(dctx->driver_ctx);
35e873
	dctx->csyspid = toks_get_driver_csyspid(dctx->driver_ctx);
971724
	dctx->ftokens = toks_get_driver_ntokens(dctx->driver_ctx);
35e873
3e9813
	svcvtbl = (dctx->driver_ctx->cctx->drvflags & TOKS_DRIVER_MODE_SERVER)
3e9813
		? toks_daemon_vtbl
3e9813
		: toks_client_vtbl;
3e9813
35e873
	if (svcvtbl == toks_daemon_vtbl)
35e873
		if ((status = toks_daemon_ctrlpid_instance(dctx)))
35e873
			ntapi->zw_terminate_process(
35e873
				NT_CURRENT_PROCESS_HANDLE,
35e873
				status);
35e873
8cf1b0
	/* service synchronization */
8cf1b0
	if (rtdata->hsync) {
8cf1b0
		ntapi->zw_set_event(rtdata->hsync,0);
8cf1b0
		ntapi->zw_close(rtdata->hsync);
8cf1b0
	}
8cf1b0
f029ca
	/* service info */
e8e83b
	if (svcvtbl == toks_daemon_vtbl)
e8e83b
		toks_log_service_info(dctx);
f029ca
3187cb
	/* pidmap object directory */
3187cb
	if ((status = toks_server_init_pidmap_object_directory(rtdata)))
3187cb
		return status;
3187cb
3187cb
	/* pidmap daemon symlink */
3187cb
	if ((status = toks_init_pidmap_target_symlink(dctx)))
3187cb
		return status;
3187cb
3187cb
	/* ntpipc object directory */
3187cb
	if ((status = toks_server_init_ntpipc_object_directory(rtdata)))
3187cb
		return status;
3187cb
3187cb
	/* ntpipc daemon symlink */
3187cb
	if ((status = toks_init_ntpipc_target_symlink(dctx)))
3187cb
		return status;
3187cb
5e5175
	/* init */
9985a1
	request = &dctx->request;
9985a1
	reply   = &dctx->reply;
9985a1
5e5175
	ntapi->tt_aligned_block_memset(
5e5175
		request,0,sizeof(*request));
5e5175
5e5175
	/* get first message */
5e5175
	ntapi->zw_reply_wait_receive_port(
5e5175
		dctx->hport_daemon,
5e5175
		&port_id,
5e5175
		0,(nt_port_message *)request);
5e5175
5e5175
	/* message loop */
5e5175
	do {
5e5175
		switch (request->header.msg_type) {
5e5175
			case NT_LPC_REQUEST:
5e5175
			case NT_LPC_DATAGRAM:
5e5175
				opcode = request->ttyinfo.opcode;
5e5175
				break;
5e5175
5e5175
			case NT_LPC_CONNECTION_REQUEST:
5e5175
				opcode = TOKS_DAEMON_CONNECT;
5e5175
				break;
5e5175
5e5175
			default:
5e5175
				opcode = -1;
5e5175
				break;
5e5175
		}
5e5175
5e5175
		/* dispatch */
0c1a80
		dctx->opcode = opcode;
9e552e
		dctx->noise++;
0c1a80
8b933d
		request->syncinfo.ipcsvc.keys.padding = 0;
cc692f
cc692f
		if (svcvtbl == toks_daemon_vtbl)
cc692f
			toks_log_lpc_request(
cc692f
				dctx,request);
cc692f
5e5175
		ntapi->tt_aligned_block_memcpy(
5e5175
			(uintptr_t *)reply,
5e5175
			(uintptr_t *)request,
5e5175
			sizeof(*reply));
5e5175
5e5175
		reply->header.msg_type = NT_LPC_REPLY;
5e5175
e6c547
		switch (opcode) {
e6c547
			case TOKS_DAEMON_IOCTL:
e6c547
				break;
e6c547
e6c547
			default:
e6c547
				reply->ttyinfo.opdata = reply->header.msg_id;
e6c547
		}
e6c547
5e5175
		if ((opcode >= TOKS_DAEMON_OPCODE_BASE) && (opcode < TOKS_DAEMON_OPCODE_CAP)) {
5e5175
			opcode -= TOKS_DAEMON_OPCODE_BASE;
e6c547
			reply->ttyinfo.status = svcvtbl[opcode]
e6c547
				? svcvtbl[opcode](dctx)
e6c547
				: NT_STATUS_NOT_IMPLEMENTED;
5e5175
		} else {
5e5175
			reply->ttyinfo.status   = NT_STATUS_LPC_INVALID_CONNECTION_USAGE;
5e5175
		}
5e5175
982902
		if (svcvtbl == toks_daemon_vtbl)
982902
			toks_log_lpc_reply(
982902
				dctx,reply);
982902
5e5175
		ntapi->tt_aligned_block_memset(
5e5175
			request,0,sizeof(*request));
5e5175
e6c547
		if (!reply->ttyinfo.opdata)
5e5175
			ntapi->zw_reply_wait_receive_port(
5e5175
				dctx->hport_daemon,
5e5175
				&port_id,
5e5175
				0,&request->header);
5e5175
		else if (reply->header.client_id.process_id == rtdata->cid_self.process_id)
5e5175
			ntapi->zw_reply_wait_receive_port(
5e5175
				dctx->hport_daemon,
5e5175
				&port_id,
5e5175
				&reply->header,
5e5175
				&request->header);
5e5175
		else {
5e5175
			ntapi->zw_reply_port(
5e5175
				dctx->hport_daemon,
5e5175
				&reply->header);
5e5175
5e5175
			ntapi->zw_reply_wait_receive_port(
5e5175
				dctx->hport_daemon,
5e5175
				&port_id,
5e5175
				0,&request->header);
5e5175
		}
5e5175
	} while (request->header.msg_id);
5e5175
5e5175
	return NT_STATUS_INTERNAL_ERROR;
5e5175
}