/*********************************************************/
/* 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_release(struct toks_token * token)
{
void * hport;
struct _nt_tty_ipc_msg msg;
uint32_t * keys;
hport = token->client.hdaemon;
keys = token->keys.key;
ntapi->tt_aligned_block_memset(
&msg,0,sizeof(msg));
msg.header.msg_type = NT_LPC_NEW_MESSAGE;
msg.header.data_size = sizeof(msg.data);
msg.header.msg_size = sizeof(msg);
msg.data.ttyinfo.opcode = TOKS_DAEMON_RELEASE;
msg.data.ipcinfo.ipckeys[0] = keys[0];
msg.data.ipcinfo.ipckeys[1] = keys[1];
msg.data.ipcinfo.ipckeys[2] = keys[2];
msg.data.ipcinfo.ipckeys[3] = keys[3];
msg.data.ipcinfo.ipckeys[4] = keys[4];
msg.data.ipcinfo.ipckeys[5] = keys[5];
ntapi->zw_request_wait_reply_port(
hport,&msg,&msg);
}
static int32_t toks_daemon_client_wait(void * rapunzel)
{
struct toks_token * token;
struct toks_client_ctx * client;
void * hduo[2];
token = (struct toks_token *)rapunzel;
client = &token->client;
ntapi->zw_set_event(client->hswap,0);
hduo[0] = client->hprocess;
hduo[1] = client->halert;
ntapi->zw_wait_for_multiple_objects(
2,hduo,
NT_WAIT_ANY,
NT_SYNC_NON_ALERTABLE,
0);
ntapi->zw_close(client->hprocess);
ntapi->zw_close(client->hport);
ntapi->zw_close(client->halert);
toks_daemon_token_release(token);
return ntapi->zw_terminate_thread(
NT_CURRENT_THREAD_HANDLE,
NT_STATUS_SUCCESS);
}
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_token_instance(
struct toks_token * token,
struct toks_client_ctx * client)
{
int32_t status;
nt_thread_params params;
if ((status = ntapi->tt_create_private_event(
&client->hswap,
NT_NOTIFICATION_EVENT,
NT_EVENT_NOT_SIGNALED)))
return status;
status = ntapi->tt_create_private_event(
&client->halert,
NT_NOTIFICATION_EVENT,
NT_EVENT_NOT_SIGNALED);
if (status) {
ntapi->zw_close(client->hswap);
return status;
}
token->self = token;
token->client.hprocess = client->hprocess;
token->client.hswap = client->hswap;
token->client.halert = client->halert;
token->client.hdaemon = client->hdaemon;
token->client.cid.process_id = client->cid.process_id;
token->client.cid.thread_id = client->cid.thread_id;
ntapi->tt_aligned_block_memset(
¶ms,0,sizeof(params));
params.hprocess = NT_CURRENT_PROCESS_HANDLE;
params.start = toks_daemon_client_wait;
params.ext_ctx = token;
params.ext_ctx_size = sizeof(*token);
params.stack_size_commit = 4 * 1024;
params.stack_size_reserve = 4 * 1024;
params.creation_flags = NT_CREATE_LOCAL_THREAD;
if ((status = ntapi->tt_create_thread(¶ms))) {
toks_daemon_token_reset(token);
ntapi->zw_close(client->hswap);
ntapi->zw_close(client->halert);
return status;
}
status = ntapi->zw_wait_for_single_object(
client->hswap,
NT_SYNC_NON_ALERTABLE,
0);
ntapi->zw_close(client->hswap);
if (status) {
toks_daemon_token_reset(token);
ntapi->zw_close(client->halert);
return status;
}
token->client.hinstance = params.hthread;
return NT_STATUS_SUCCESS;
}
static int32_t toks_daemon_queue(struct toks_daemon_ctx * dctx, void * hcaller, void * hprocess)
{
int nwaiters;
struct toks_waiter * waiter;
nt_tty_port_msg * msg;
void * hevent;
int32_t status;
msg = &dctx->reply;
nwaiters = toks_get_driver_nwaiters(dctx->driver_ctx);
if (nwaiters == TOKS_MAX_WAITERS)
return NT_STATUS_TIMEOUT;
status = ntapi->zw_duplicate_object(
hcaller,
msg->ipcinfo.hevent,
NT_CURRENT_PROCESS_HANDLE,
&hevent,
NT_EVENT_QUERY_STATE|NT_EVENT_MODIFY_STATE,
0,0);
ntapi->zw_close(hcaller);
if (status) {
ntapi->zw_close(hprocess);
return status;
}
if ((status = ntapi->zw_reset_event(hevent,&(int){0}))) {
ntapi->zw_close(hprocess);
ntapi->zw_close(hevent);
return status;
}
waiter = dctx->waiter_next;
waiter->client.hprocess = hprocess;
waiter->client.hevent = hevent;
toks_set_driver_nwaiters(
dctx->driver_ctx,
++nwaiters);
dctx->waiter_next++;
if (dctx->waiter_next == dctx->waiter_cap)
dctx->waiter_next = dctx->waiter_base;
ntapi->tt_generic_memcpy(
&waiter->msg,msg,
sizeof(*msg));
return NT_STATUS_PENDING;
}
int32_t __stdcall toks_daemon_acquire(struct toks_daemon_ctx * dctx)
{
int32_t status;
nt_tty_port_msg * msg;
void * hcaller;
struct toks_client_ctx client;
nt_oa oa;
struct toks_token * token;
struct toks_token * tocap;
nt_filetime pcnt;
msg = &dctx->reply;
client.hport = 0;
client.hprocess = 0;
client.hswap = 0;
client.hdaemon = dctx->hport_internal_client;
client.cid.process_id = msg->header.client_id.process_id;
client.cid.thread_id = 0;
client.tokpid = 0;
oa.len = sizeof(oa);
oa.root_dir = 0;
oa.obj_name = 0;
oa.obj_attr = 0;
oa.sec_desc = 0;
oa.sec_qos = 0;
if (dctx->opcode == TOKS_DAEMON_ACQUIRE) {
if ((dctx->reqtokpid = msg->ipcinfo.ctrlsvc.keys.reserved)) {
if ((status = toks_daemon_pidopen(dctx)))
return status;
client.tokpid = dctx->reqtokpid;
client.cid.process_id = dctx->reqsyspid;
}
if ((status = ntapi->zw_open_process(
&client.hprocess,
NT_PROCESS_SYNCHRONIZE
| NT_PROCESS_QUERY_INFORMATION,
&oa,&client.cid)))
return status;
}
token = toks_get_driver_tokens(dctx->driver_ctx);
tocap = &token[toks_get_driver_ntokens(dctx->driver_ctx)];
for (; token->self && (token<tocap); )
token++;
if ((token == tocap) && !msg->ipcinfo.hevent) {
ntapi->zw_close(client.hprocess);
return NT_STATUS_TIMEOUT;
}
toks_query_performance_counters(dctx->driver_ctx,&pcnt);
if (token == tocap) {
status = ntapi->zw_open_process(
&hcaller,
NT_PROCESS_SYNCHRONIZE
| NT_PROCESS_DUP_HANDLE
| NT_PROCESS_QUERY_INFORMATION,
&oa,&msg->header.client_id);
if (status) {
ntapi->zw_close(client.hprocess);
return status;
}
msg->ipcinfo.ipckeys[0] = ntapi->tt_buffer_crc32(
msg->header.msg_id,
&pcnt,sizeof(pcnt));
msg->ipcinfo.ipckeys[1] = ntapi->tt_buffer_crc32(
msg->header.msg_id,
&msg->header,sizeof(msg->header));
msg->ipcinfo.ipckeys[2] = ntapi->tt_buffer_crc32(
msg->header.msg_id,
&msg->ipcinfo,sizeof(msg->ipcinfo));
msg->ipcinfo.ipckeys[3] = ntapi->tt_buffer_crc32(
msg->header.msg_id,
&client,sizeof(client));
msg->ipcinfo.ipckeys[4] = ntapi->tt_buffer_crc32(
msg->header.msg_id,
toks_get_driver_tokens(dctx->driver_ctx),
toks_get_driver_ntokens(dctx->driver_ctx)
* sizeof(struct toks_token));
msg->ipcinfo.ipckeys[5] = ntapi->tt_buffer_crc32(
msg->header.msg_id,
&token->keys,sizeof(token->keys));
return toks_daemon_queue(
dctx,hcaller,
client.hprocess);
}
if (dctx->opcode == TOKS_DAEMON_RELEASE) {
client.hprocess = msg->ttyinfo.exarg;
token->keys.key[0] = msg->ipcinfo.ipckeys[0];
token->keys.key[1] = msg->ipcinfo.ipckeys[1];
token->keys.key[2] = msg->ipcinfo.ipckeys[2];
token->keys.key[3] = msg->ipcinfo.ipckeys[3];
token->keys.key[4] = msg->ipcinfo.ipckeys[4];
token->keys.key[5] = msg->ipcinfo.ipckeys[5];
} else {
token->keys.key[0] = ntapi->tt_buffer_crc32(
msg->header.msg_id,
&pcnt,sizeof(pcnt));
token->keys.key[1] = ntapi->tt_buffer_crc32(
msg->header.msg_id,
&msg->header,sizeof(msg->header));
token->keys.key[2] = ntapi->tt_buffer_crc32(
msg->header.msg_id,
&msg->ipcinfo,sizeof(msg->ipcinfo));
token->keys.key[3] = ntapi->tt_buffer_crc32(
msg->header.msg_id,
&client,sizeof(client));
token->keys.key[4] = ntapi->tt_buffer_crc32(
msg->header.msg_id,
toks_get_driver_tokens(dctx->driver_ctx),
toks_get_driver_ntokens(dctx->driver_ctx)
* sizeof(struct toks_token));
token->keys.key[5] = ntapi->tt_buffer_crc32(
msg->header.msg_id,
&token->keys,sizeof(token->keys));
msg->ipcinfo.ipckeys[0] = token->keys.key[0];
msg->ipcinfo.ipckeys[1] = token->keys.key[1];
msg->ipcinfo.ipckeys[2] = token->keys.key[2];
msg->ipcinfo.ipckeys[3] = token->keys.key[3];
msg->ipcinfo.ipckeys[4] = token->keys.key[4];
msg->ipcinfo.ipckeys[5] = token->keys.key[5];
}
if ((status = toks_daemon_token_instance(token,&client))) {
toks_daemon_token_reset(token);
ntapi->zw_close(client.hprocess);
return status;
}
return NT_STATUS_SUCCESS;
}