/********************************************************/
/* ntapi: Native API core library */
/* Copyright (C) 2013--2017 Z. Gilboa */
/* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */
/********************************************************/
#include <ntapi/nt_atomic.h>
#include <ntapi/nt_status.h>
#include <ntapi/nt_thread.h>
#include <ntapi/nt_port.h>
#include <ntapi/nt_daemon.h>
#include <ntapi/ntapi.h>
#include "ntapi_impl.h"
int32_t __attr_hidden__ __ntapi_tt_seh_frame(void *, void *, void *, int32_t (*)(nt_daemon_params *));
static int32_t __ntapi_dsr_once(nt_daemon_params * params);
static int32_t __ntapi_dsr_start(nt_daemon_params * params);
int32_t __stdcall __ntapi_dsr_init(nt_daemon_params * params)
{
int32_t status;
nt_thread_params tparams;
/* report status */
at_store_32(
¶ms->exit_code_daemon_loop,
NT_STATUS_PENDING);
at_store_32(
¶ms->exit_code_daemon_start,
NT_STATUS_PENDING);
at_store_32(
¶ms->exit_code_internal_client,
NT_STATUS_PENDING);
/* port_keys */
if (params->flags & NT_DSR_INIT_GENERATE_KEYS)
if ((status = __ntapi->tt_port_generate_keys(params->port_keys)))
return status;
/* port_name_keys */
if (params->flags & NT_DSR_INIT_FORMAT_KEYS)
__ntapi->tt_port_format_keys(
params->port_keys,
params->port_name_keys);
/* 'port-created' event */
if (!params->hevent_daemon_port) {
if ((status = __ntapi->tt_create_private_event(
¶ms->hevent_daemon_port,
NT_NOTIFICATION_EVENT,
NT_EVENT_NOT_SIGNALED)))
return status;
if (params->pevent_daemon_port)
at_store(
(intptr_t *)params->pevent_daemon_port,
(intptr_t)params->hevent_daemon_port);
}
/* 'daemon-is-ready' event */
if (!params->hevent_daemon_ready) {
if ((status = __ntapi->tt_create_private_event(
¶ms->hevent_daemon_ready,
NT_NOTIFICATION_EVENT,
NT_EVENT_NOT_SIGNALED)))
return status;
if (params->pevent_daemon_ready)
at_store(
(intptr_t *)params->pevent_daemon_ready,
(intptr_t)params->hevent_daemon_ready);
}
/* 'internal-client-is-ready' event */
if (!params->hevent_internal_client_ready) {
if ((status = __ntapi->tt_create_private_event(
¶ms->hevent_internal_client_ready,
NT_NOTIFICATION_EVENT,
NT_EVENT_NOT_SIGNALED)))
return status;
if (params->pevent_internal_client_ready)
at_store(
(intptr_t *)params->pevent_internal_client_ready,
(intptr_t)params->hevent_internal_client_ready);
}
/* memory barrier */
__ntapi->tt_aligned_block_memlock(
params,
sizeof(*params));
__ntapi->tt_aligned_block_memlock(
params->port_name,
sizeof(*params->port_name));
/* daemon dedicated thread: general parameters */
__ntapi->tt_aligned_block_memset(
&tparams,0,sizeof(tparams));
tparams.start = (nt_thread_start_routine *)__ntapi_dsr_start;
tparams.arg = params;
/* daemon dedicated thread: stack parameters (optional) */
tparams.stack_size_commit = params->stack_size_commit;
tparams.stack_size_reserve = params->stack_size_reserve;
tparams.stack_info = params->stack_info;
/* daemon dedicated thread: create */
if ((status = __ntapi->tt_create_local_thread(&tparams)))
return status;
at_store(
(intptr_t *)¶ms->hthread_daemon_loop,
(intptr_t)tparams.hthread);
/* daemon dedicated thread: actual stack size */
params->stack_size_commit = tparams.stack_size_commit;
params->stack_size_reserve = tparams.stack_size_reserve;
/* wait for the port to be created */
if ((status = __ntapi->zw_wait_for_single_object(
params->hevent_daemon_port,
NT_SYNC_NON_ALERTABLE,0)))
return status;
/* overcome potential scheduling bug in recent (10.0) kernel */
while (params->exit_code_daemon_start == NT_STATUS_PENDING)
__ntapi->zw_delay_execution(
NT_SYNC_NON_ALERTABLE,
&(nt_timeout){{0,0}});
/* verify the port's successful creation */
if (at_locked_xadd_32(¶ms->exit_code_daemon_start,0))
return NT_STATUS_PORT_NOT_SET;
/* internal connection task-specific thread */
__ntapi->tt_aligned_block_memset(
&tparams,0,sizeof(tparams));
tparams.start = (nt_thread_start_routine *)__ntapi_dsr_internal_client_connect;
tparams.arg = params;
if ((status = __ntapi->tt_create_local_thread(&tparams)))
return status;
at_store(
(intptr_t *)¶ms->hthread_internal_client,
(intptr_t)tparams.hthread);
/* wait for the task-specific thread to exit */
if ((status = __ntapi->zw_wait_for_single_object(
params->hthread_internal_client,
NT_SYNC_NON_ALERTABLE,0)))
return status;
/* overcome potential scheduling bug in recent (10.0) kernel */
while (params->exit_code_internal_client == NT_STATUS_PENDING)
__ntapi->zw_delay_execution(
NT_SYNC_NON_ALERTABLE,
&(nt_timeout){{0,0}});
/* verify a successful internal connection */
if (at_locked_xadd_32(¶ms->exit_code_internal_client,0))
return params->exit_code_internal_client;
/* all_done */
__ntapi->zw_set_event(
params->hevent_daemon_ready,
0);
if (params->flags & NT_DSR_INIT_CLOSE_EVENTS) {
__ntapi->zw_close(params->hevent_daemon_port);
__ntapi->zw_close(params->hevent_daemon_ready);
__ntapi->zw_close(params->hevent_internal_client_ready);
}
return NT_STATUS_SUCCESS;;
}
/* __ntapi_dsr_start executes in the daemon's dedicated thread */
static int32_t __ntapi_dsr_start_impl(nt_daemon_params * params)
{
int32_t status;
void * ctx;
int32_t (__stdcall *loop)(void *);
ctx = params->daemon_loop_context;
loop = params->daemon_loop_routine;
if ((status = __ntapi_dsr_once(params)))
return status;
if ((status = __ntapi_dsr_create_port(params)))
return status;
if ((status = __ntapi_dsr_connect_internal_client(params)))
return status;
if ((status = loop(ctx)))
return status;
return NT_STATUS_SUCCESS;
}
static int32_t __ntapi_dsr_start_routine(nt_daemon_params * params)
{
at_store_32(
¶ms->exit_code_daemon_loop,
NT_STATUS_MORE_PROCESSING_REQUIRED);
return __ntapi->zw_terminate_thread(
NT_CURRENT_THREAD_HANDLE,
__ntapi_dsr_start_impl(params));
}
static int32_t __ntapi_dsr_start(nt_daemon_params * params)
{
return __ntapi_tt_seh_frame(
params,0,0,
__ntapi_dsr_start_routine);
}
/* __ntapi_dsr_once executes in the daemon's dedicated thread */
static int32_t __ntapi_dsr_once(nt_daemon_params * params)
{
int32_t status;
if (!params->daemon_once_routine)
return NT_STATUS_SUCCESS;
if ((status = params->daemon_once_routine(params->daemon_loop_context)))
at_store_32(
¶ms->exit_code_daemon_start,
status);
return status;
}
/* __ntapi_dsr_create_port executes in the daemon's dedicated thread */
static int32_t __stdcall __ntapi_dsr_create_port_exit(
nt_daemon_params * params,
int32_t status)
{
at_store_32(
¶ms->exit_code_daemon_start,
status);
__ntapi->zw_set_event(
params->hevent_daemon_port,
0);
return status;
}
int32_t __stdcall __ntapi_dsr_create_port(nt_daemon_params * params)
{
int32_t status;
nt_object_attributes oa;
nt_security_quality_of_service sqos;
nt_unicode_string server_name;
/* init server_name */
server_name.strlen = (uint16_t)__ntapi->tt_string_null_offset_short((int16_t *)params->port_name);
server_name.maxlen = 0;
server_name.buffer = params->port_name;
/* init security structure */
sqos.length = sizeof(sqos);
sqos.impersonation_level = NT_SECURITY_IMPERSONATION;
sqos.context_tracking_mode = NT_SECURITY_TRACKING_DYNAMIC;
sqos.effective_only = 1;
/* init the port's object attributes */
oa.len = sizeof(oa);
oa.root_dir = 0;
oa.obj_name = &server_name;
oa.obj_attr = 0;
oa.sec_desc = params->port_sd;
oa.sec_qos = &sqos;
/* create the port */
if ((status = __ntapi->zw_create_port(
¶ms->hport_daemon,
&oa,0,(uint32_t)params->port_msg_size,
0)))
return __ntapi_dsr_create_port_exit(
params,status);
/* return port info */
if (params->pport_daemon)
at_store(
(intptr_t *)params->pport_daemon,
(intptr_t)params->hport_daemon);
/* set status */
at_store_32(
¶ms->exit_code_daemon_start,
NT_STATUS_SUCCESS);
/* signal the port-created event */
__ntapi->zw_set_event(
params->hevent_daemon_port,
0);
return NT_STATUS_SUCCESS;
}