/********************************************************/
/* ntapi: Native API core library */
/* Copyright (C) 2013--2021 SysDeer Technologies, LLC */
/* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */
/********************************************************/
#include <psxtypes/psxtypes.h>
#include <ntapi/ntapi.h>
#include "ntapi_impl.h"
static int32_t __fastcall __tty_create_session_return(
void * hready,
nt_create_process_params * params,
int32_t status)
{
if (params->hprocess && status)
__ntapi->zw_terminate_process(
params->hprocess,
NT_STATUS_UNEXPECTED_IO_ERROR);
__ntapi->zw_close(hready);
__ntapi->zw_close(params->hprocess);
__ntapi->zw_close(params->hthread);
return status;
}
int32_t __stdcall __ntapi_tty_create_session(
__out void ** hport,
__out nt_port_name * port_name,
__in nt_tty_session_type type,
__in nt_tty_session_subtype subtype,
__in const nt_guid * guid __optional,
__in wchar16_t * image_name,
__in void * htty __optional)
{
nt_status status;
ntapi_internals * __internals;
void * shport;
nt_port_name sport_name;
nt_tty_server_basic_info ttyinfo;
nt_iosb iosb;
nt_port_attr port_attr;
nt_runtime_data * rtdata;
nt_runtime_data ssattr;
nt_runtime_data_block rtblock;
nt_create_process_params params;
nt_event_basic_information eready;
/* abi/api */
(void)subtype;
/* validate */
if (!image_name)
return NT_STATUS_INVALID_PARAMETER;
/* init */
__internals = __ntapi_internals();
rtdata = __internals->rtdata;
__ntapi->tt_aligned_block_memset(
&port_attr,0,sizeof(port_attr));
__ntapi->tt_aligned_block_memset(
&ssattr,0,sizeof(ssattr));
/* port type */
if (guid) {
if ((status = __ntapi->tt_port_type_from_guid(
&port_attr.type,
&port_attr.subtype,
guid)))
return status;
} else {
port_attr.type = NT_PORT_TYPE_SUBSYSTEM;
}
/* port subtype */
switch (type) {
case NT_TTY_SESSION_PRIMARY:
port_attr.subtype = NT_PORT_SUBTYPE_DEFAULT;
if (!hport)
hport = &__internals->hport_tty_session;
if (!port_name)
port_name = __internals->subsystem;
break;
case NT_TTY_SESSION_SECONDARY:
port_attr.subtype = NT_PORT_SUBTYPE_DEFAULT;
if (!hport)
hport = &shport;
if (!port_name)
port_name = &sport_name;
break;
case NT_TTY_SESSION_PRIVATE:
port_attr.subtype = NT_PORT_SUBTYPE_PRIVATE;
break;
default:
return NT_STATUS_INVALID_PARAMETER;
}
/* port guid */
if (guid)
__ntapi->tt_guid_copy(
&port_attr.guid,
guid);
else
__ntapi->tt_port_guid_from_type(
&port_attr.guid,
port_attr.type,
port_attr.subtype);
/* port keys */
if ((status = __ntapi->tt_port_generate_keys(&port_attr.keys)))
return status;
/* port name */
__ntapi->tt_port_name_from_attr(
port_name,
&port_attr);
/* parent session) */
if (htty && (htty != NT_INVALID_HANDLE_VALUE)) {
if ((status = __ntapi->tty_query_information_server(
htty,&iosb,
&ttyinfo,sizeof(ttyinfo),
NT_TTY_SERVER_BASIC_INFORMATION)))
return status;
ssattr.tty_type = ttyinfo.attr.type;
ssattr.tty_subtype = ttyinfo.attr.subtype;
ssattr.tty_keys[0] = ttyinfo.attr.keys.key[0];
ssattr.tty_keys[1] = ttyinfo.attr.keys.key[1];
ssattr.tty_keys[2] = ttyinfo.attr.keys.key[2];
ssattr.tty_keys[3] = ttyinfo.attr.keys.key[3];
ssattr.tty_keys[4] = ttyinfo.attr.keys.key[4];
ssattr.tty_keys[5] = ttyinfo.attr.keys.key[5];
__ntapi->tt_guid_copy(
&ssattr.tty_guid,
&ttyinfo.attr.guid);
}
/* subsystem attributes */
__ntapi->tt_guid_copy(
&ssattr.abi,
&(nt_guid)NT_PROCESS_GUID_RTDATA);
ssattr.srv_type = port_attr.type;
ssattr.srv_subtype = port_attr.subtype;
ssattr.srv_keys[0] = port_attr.keys.key[0];
ssattr.srv_keys[1] = port_attr.keys.key[1];
ssattr.srv_keys[2] = port_attr.keys.key[2];
ssattr.srv_keys[3] = port_attr.keys.key[3];
ssattr.srv_keys[4] = port_attr.keys.key[4];
ssattr.srv_keys[5] = port_attr.keys.key[5];
__ntapi->tt_guid_copy(
&ssattr.srv_guid,
&port_attr.guid);
if ((status = __ntapi->tt_create_private_event(
&ssattr.hserver,
NT_NOTIFICATION_EVENT,
NT_EVENT_NOT_SIGNALED)))
return status;
/* server chain */
if (rtdata->srv_type) {
ssattr.ppid_type = rtdata->srv_type;
ssattr.ppid_subtype = rtdata->srv_subtype;
ssattr.ppid_keys[0] = rtdata->srv_keys[0];
ssattr.ppid_keys[1] = rtdata->srv_keys[1];
ssattr.ppid_keys[2] = rtdata->srv_keys[2];
ssattr.ppid_keys[3] = rtdata->srv_keys[3];
ssattr.ppid_keys[4] = rtdata->srv_keys[4];
ssattr.ppid_keys[5] = rtdata->srv_keys[5];
__ntapi->tt_guid_copy(
&ssattr.ppid_guid,
&rtdata->srv_guid);
}
/* create subsystem process */
rtblock.addr = &ssattr;
rtblock.size = sizeof(ssattr);
rtblock.remote_addr = 0;
rtblock.remote_size = 0;
rtblock.flags = NT_RUNTIME_DATA_DUPLICATE_SESSION_HANDLES;
__ntapi->tt_aligned_block_memset(
¶ms,0,sizeof(params));
params.image_name = image_name;
params.rtblock = &rtblock;
params.hsession = htty;
if ((status = __ntapi->tt_create_native_process(¶ms)))
return __tty_create_session_return(ssattr.hserver,¶ms,status);
__ntapi->zw_wait_for_multiple_objects(
2,
(void *[]){ssattr.hserver,params.hprocess},
NT_WAIT_ANY,
NT_SYNC_NON_ALERTABLE,
0);
if ((status = __ntapi->zw_query_event(
ssattr.hserver,
NT_EVENT_BASIC_INFORMATION,
&eready,
sizeof(eready),
&(size_t){0})))
return __tty_create_session_return(ssattr.hserver,¶ms,status);
if (!eready.signal_state)
return __tty_create_session_return(ssattr.hserver,¶ms,NT_STATUS_SYSTEM_PROCESS_TERMINATED);
/* connect to subsystem */
if ((status = __ntapi->tty_connect(
hport,
&port_name->base_named_objects[0],
NT_SECURITY_IMPERSONATION)))
return __tty_create_session_return(ssattr.hserver,¶ms,status);
/* finalize primary session */
if (type == NT_TTY_SESSION_PRIMARY) {
if (hport != &__internals->hport_tty_session)
__internals->hport_tty_session = *hport;
if (port_name != __internals->subsystem)
__ntapi->tt_memcpy_utf16(
__internals->subsystem->base_named_objects,
port_name->base_named_objects,
sizeof(*port_name));
};
return __tty_create_session_return(ssattr.hserver,¶ms,NT_STATUS_SUCCESS);
}