/********************************************************/ /* ntapi: Native API core library */ /* Copyright (C) 2013--2021 Z. Gilboa */ /* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */ /********************************************************/ #include #include #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); }