Blob Blame History Raw
/*********************************************************/
/*  toksvc: a framework-native token broker service      */
/*  Copyright (C) 2020  Z. Gilboa                        */
/*  Released under GPLv2 and GPLv3; see COPYING.TOKSVC.  */
/*********************************************************/

#include <psxtypes/psxtypes.h>
#include <ntapi/ntapi.h>

#include <toksvc/toksvc.h>
#include "toksvc_daemon_impl.h"
#include "toksvc_driver_impl.h"

static void toks_daemon_token_reset(struct toks_token * token)
{
	token->self        = 0;
	token->keys.key[0] = 0;
	token->keys.key[1] = 0;
	token->keys.key[2] = 0;
	token->keys.key[3] = 0;
	token->keys.key[4] = 0;
	token->keys.key[5] = 0;
}

static int32_t toks_daemon_unqueue(struct toks_daemon_ctx * dctx)
{
	int                         status;
	int                         nwaiters;
	struct toks_waiter *        waiter;
	nt_tty_port_msg *           msg;
	nt_tty_port_msg             cmsg;
	void *                      hcaller;

	msg      = &dctx->reply;
	nwaiters = toks_get_driver_nwaiters(dctx->driver_ctx);

	if ((nwaiters == 0) || (dctx->ftokens == 0))
		return NT_STATUS_SUCCESS;



	waiter = dctx->waiter_first;

	toks_set_driver_nwaiters(
		dctx->driver_ctx,
		--nwaiters);

	dctx->waiter_first++;

	if (dctx->waiter_first == dctx->waiter_cap)
		dctx->waiter_first = dctx->waiter_base;



	if (!waiter->msg.header.msg_id)
		return NT_STATUS_CANCELLED;


	if ((hcaller = waiter->client.hcaller)) {
		status = ntapi->zw_wait_for_single_object(
			hcaller,
			NT_SYNC_NON_ALERTABLE,
			&(nt_timeout){.quad=0});

		ntapi->zw_close(hcaller);

		switch (status) {
			case NT_STATUS_TIMEOUT:
				break;

			default:
				waiter->msg.header.msg_id = 0;
				return NT_STATUS_REQUEST_ABORTED;
		}
	}


	ntapi->tt_generic_memcpy(
		&cmsg,msg,
		sizeof(*msg));

	ntapi->tt_generic_memcpy(
		msg,&waiter->msg,
		sizeof(*msg));

	msg->ttyinfo.exarg  = waiter->client.hprocess;
	msg->ttyinfo.status = toks_daemon_acquire(dctx);
	status              = msg->ttyinfo.status;

	ntapi->zw_set_event(waiter->client.hevent,0);
	ntapi->zw_close(waiter->client.hevent);

	ntapi->tt_generic_memcpy(
		msg,&cmsg,
		sizeof(*msg));

	return status;
}

static int toks_daemon_unqueue_ioctl(struct toks_daemon_ctx * dctx)
{
	int ntokens = toks_get_driver_ntokens(dctx->driver_ctx);

	dctx->opcode = TOKS_DAEMON_RELEASE;

	while (dctx->utokens < ntokens) {
		if (toks_get_driver_nwaiters(dctx->driver_ctx) == 0) {
			dctx->opcode = TOKS_DAEMON_IOCTL;
			return NT_STATUS_SUCCESS;
		}

		toks_daemon_unqueue(dctx);
	}

	dctx->opcode = TOKS_DAEMON_IOCTL;

	return NT_STATUS_SUCCESS;
}

int32_t __stdcall toks_daemon_release(struct toks_daemon_ctx * dctx)
{
	nt_tty_port_msg *           msg;
	struct toks_token *         token;
	struct toks_token *         toptr;
	struct toks_token *         tocap;
	uint32_t *                  keys;

	if (dctx->opcode == TOKS_DAEMON_IOCTL)
		return toks_daemon_unqueue_ioctl(dctx);

	msg   = &dctx->reply;
	keys  = msg->syncinfo.ipckeys;

	toptr = toks_get_driver_tokens(dctx->driver_ctx);
	tocap = &toptr[toks_get_driver_atokens(dctx->driver_ctx)];

	for (token=0; !token && (toptr<tocap); toptr++)
		if ((toptr->self)
				&& (toptr->keys.key[0] == keys[0])
				&& (toptr->keys.key[1] == keys[1])
				&& (toptr->keys.key[2] == keys[2])
				&& (toptr->keys.key[3] == keys[3])
				&& (toptr->keys.key[4] == keys[4])
				&& (toptr->keys.key[5] == keys[5]))
			token = toptr;

	if (!token)
		return NT_STATUS_INVALID_PARAMETER;

	if (--dctx->utokens < toks_get_driver_ntokens(dctx->driver_ctx))
		dctx->ftokens++;

	toks_daemon_token_reset(token);

	ntapi->zw_alert_thread(token->client.hinstance);
	ntapi->zw_close(token->client.hinstance);

	do {
		(void)0;
	} while (toks_daemon_unqueue(dctx));

	return NT_STATUS_SUCCESS;
}