Blame src/pty/ntapi_pty_fd.c

dd89bb
/********************************************************/
dd89bb
/*  ntapi: Native API core library                      */
64e606
/*  Copyright (C) 2013--2021  SysDeer Technologies, LLC */
dd89bb
/*  Released under GPLv2 and GPLv3; see COPYING.NTAPI.  */
dd89bb
/********************************************************/
dd89bb
dd89bb
#include <psxtypes/psxtypes.h>
ae5d60
#include <ntapi/nt_atomic.h>
dd89bb
#include <ntapi/nt_port.h>
dd89bb
#include <ntapi/nt_tty.h>
dd89bb
#include <ntapi/ntapi.h>
dd89bb
#include "ntapi_impl.h"
dd89bb
#include "ntapi_pty.h"
dd89bb
dd89bb
static int32_t __stdcall __ntapi_pty_open_close(
dd89bb
	nt_pty *	pty,
dd89bb
	nt_iosb *	iosb,
dd89bb
	int32_t		opcode)
dd89bb
{
dd89bb
	int32_t		status;
dd89bb
	nt_pty_fd_msg	msg;
dd89bb
dd89bb
	__ntapi->tt_aligned_block_memset(&msg,0,sizeof(msg));
dd89bb
dd89bb
	msg.header.msg_type	= NT_LPC_NEW_MESSAGE;
dd89bb
	msg.header.data_size	= sizeof(msg.data);
dd89bb
	msg.header.msg_size	= sizeof(msg);
dd89bb
	msg.data.ttyinfo.opcode	= opcode;
dd89bb
dd89bb
	msg.data.fdinfo.hpty	= pty->hpty;
dd89bb
	msg.data.fdinfo.access	= pty->access;
dd89bb
	msg.data.fdinfo.flags	= pty->flags;
dd89bb
	msg.data.fdinfo.share	= pty->share;
dd89bb
	msg.data.fdinfo.options	= pty->options;
dd89bb
dd89bb
	msg.data.fdinfo.luid.high = pty->luid.high;
dd89bb
	msg.data.fdinfo.luid.low  = pty->luid.low;
dd89bb
dd89bb
	__ntapi_tt_guid_copy(
dd89bb
		&msg.data.fdinfo.guid,
dd89bb
		&pty->guid);
dd89bb
dd89bb
	if ((status = __ntapi->zw_request_wait_reply_port(pty->hport,&msg,&msg)))
dd89bb
		return status;
dd89bb
	else if (msg.data.ttyinfo.status)
dd89bb
		return msg.data.ttyinfo.status;
dd89bb
dd89bb
	pty->hpty	  = msg.data.fdinfo.hpty;
dd89bb
	pty->section	  = msg.data.fdinfo.section;
dd89bb
	pty->section_size = msg.data.fdinfo.section_size;
dd89bb
	pty->luid.high	  = msg.data.fdinfo.luid.high;
dd89bb
	pty->luid.low	  = msg.data.fdinfo.luid.low;
dd89bb
	iosb->status	  = msg.data.ttyinfo.status;
dd89bb
	iosb->info	  = 0;
dd89bb
dd89bb
	return NT_STATUS_SUCCESS;
dd89bb
}
dd89bb
dd89bb
dd89bb
static int32_t __fastcall __ntapi_pty_free(nt_pty * pty)
dd89bb
{
dd89bb
	void *	addr;
dd89bb
	size_t	size;
dd89bb
dd89bb
	/* unmap section */
dd89bb
	if (pty->section_addr)
dd89bb
		__ntapi->zw_unmap_view_of_section(
dd89bb
			NT_CURRENT_PROCESS_HANDLE,
dd89bb
			pty->section_addr);
dd89bb
dd89bb
	/* free control block */
dd89bb
	addr = pty->addr;
dd89bb
	size = pty->size;
dd89bb
dd89bb
	return __ntapi->zw_free_virtual_memory(
dd89bb
		NT_CURRENT_PROCESS_HANDLE,
dd89bb
		&addr,
dd89bb
		&size,
dd89bb
		NT_MEM_RELEASE);
dd89bb
}
dd89bb
dd89bb
dd89bb
static int32_t __fastcall __ntapi_pty_fail(nt_pty * pty,int32_t status)
dd89bb
{
dd89bb
	__ntapi_pty_free(pty);
dd89bb
	return status;
dd89bb
}
dd89bb
dd89bb
dd89bb
static int32_t __fastcall __ntapi_pty_alloc(nt_pty ** pty)
dd89bb
{
dd89bb
	int32_t		status;
dd89bb
	nt_pty *	ctx;
dd89bb
	size_t		ctx_size;
dd89bb
dd89bb
	/* allocate control block */
dd89bb
	ctx = 0;
dd89bb
	ctx_size = sizeof(nt_pty);
dd89bb
dd89bb
	if ((status = __ntapi->zw_allocate_virtual_memory(
dd89bb
			NT_CURRENT_PROCESS_HANDLE,
dd89bb
			(void **)&ctx,
dd89bb
			0,&ctx_size,
dd89bb
			NT_MEM_COMMIT,
dd89bb
			NT_PAGE_READWRITE)))
dd89bb
		return status;
dd89bb
dd89bb
	/* init control block */
dd89bb
	__ntapi->tt_aligned_block_memset(
dd89bb
		ctx,0,ctx_size);
dd89bb
dd89bb
	ctx->addr = ctx;
dd89bb
	ctx->size = ctx_size;
dd89bb
ae5d60
	/* atomic lock reset */
ae5d60
	at_store_32(&ctx->lock[__PTY_READ],0);
ae5d60
	at_store_32(&ctx->lock[__PTY_WRITE],0);
ae5d60
dd89bb
	*pty = ctx;
dd89bb
	return NT_STATUS_SUCCESS;
dd89bb
}
dd89bb
dd89bb
static int32_t __ntapi_pty_connect(
dd89bb
	void *		hport,
dd89bb
	nt_pty *	ctx,
dd89bb
	nt_iosb *	iosb)
dd89bb
{
dd89bb
	int32_t status;
dd89bb
dd89bb
	ctx->hport = hport
dd89bb
		? hport
dd89bb
		: __ntapi_internals()->hport_tty_session;
dd89bb
dd89bb
	/* request */
dd89bb
	iosb = iosb ? iosb : &ctx->iosb;
dd89bb
dd89bb
	if ((status = __ntapi_pty_open_close(ctx,iosb,NT_TTY_PTY_OPEN)))
dd89bb
		return __ntapi_pty_fail(ctx,status);
dd89bb
dd89bb
	/* map section */
dd89bb
	if ((status = __ntapi->zw_map_view_of_section(
dd89bb
			ctx->section,
dd89bb
			NT_CURRENT_PROCESS_HANDLE,
dd89bb
			&ctx->section_addr,
dd89bb
			0,ctx->section_size,
dd89bb
			0,&ctx->section_size,
dd89bb
			NT_VIEW_UNMAP,0,
dd89bb
			NT_PAGE_READWRITE)))
f62cf8
		ctx->section_addr = 0;
f62cf8
f62cf8
	/* resilience */
cbd18a
	if (!ctx->section_addr)
f62cf8
		if ((status = __ntapi->zw_map_view_of_section(
f62cf8
				ctx->section,
f62cf8
				NT_CURRENT_PROCESS_HANDLE,
f62cf8
				&ctx->section_addr,
f62cf8
				0,ctx->section_size,
f62cf8
				0,&ctx->section_size,
f62cf8
				NT_VIEW_UNMAP,0,
f62cf8
				NT_PAGE_READWRITE)))
f62cf8
			return __ntapi_pty_fail(ctx,status);
dd89bb
ae5d60
	/* atomic lock reset */
ae5d60
	at_store_32(&ctx->lock[__PTY_READ],0);
ae5d60
	at_store_32(&ctx->lock[__PTY_WRITE],0);
dd89bb
dd89bb
	return NT_STATUS_SUCCESS;
dd89bb
}
dd89bb
dd89bb
47aaf2
static int32_t __ntapi_pty_open_impl(
dd89bb
	void *			hport,
dd89bb
	nt_pty **		pty,
dd89bb
	uint32_t		desired_access,
dd89bb
	nt_object_attributes*	obj_attr,
dd89bb
	nt_iosb *		iosb,
dd89bb
	uint32_t		share_access,
47aaf2
	uint32_t		open_options,
47aaf2
	nt_pty *		rpty)
dd89bb
{
dd89bb
	int32_t			status;
dd89bb
	nt_guid			guid;
dd89bb
	nt_uuid_str_utf16 *	guid_str;
dd89bb
	nt_pty *		ctx;
e9b18b
	wchar16_t *		wch;
dd89bb
e9b18b
	/* validate */
dd89bb
	if (!obj_attr || !obj_attr->obj_name || !obj_attr->obj_name->buffer)
dd89bb
		return NT_STATUS_INVALID_PARAMETER;
dd89bb
dd89bb
	if (obj_attr->obj_name->strlen != __DEVICE_PATH_PREFIX_LEN + sizeof(nt_guid_str_utf16))
dd89bb
		return NT_STATUS_OBJECT_PATH_INVALID;
dd89bb
e9b18b
	wch = obj_attr->obj_name->buffer;
dd89bb
e9b18b
	if ((wch[0] != '\\')
e9b18b
			|| (wch[1] != 'D')
e9b18b
			|| (wch[2] != 'e')
e9b18b
			|| (wch[3] != 'v')
e9b18b
			|| (wch[4] != 'i')
e9b18b
			|| (wch[5] != 'c')
e9b18b
			|| (wch[6] != 'e')
e9b18b
			|| (wch[7] != '\\'))
dd89bb
		return NT_STATUS_OBJECT_PATH_INVALID;
dd89bb
dd89bb
	guid_str = (nt_uuid_str_utf16 *)
dd89bb
		((uintptr_t)obj_attr->obj_name->buffer + __DEVICE_PATH_PREFIX_LEN);
dd89bb
701eb2
	if (__ntapi->tt_string_to_guid_utf16(guid_str,&guid))
dd89bb
		return NT_STATUS_OBJECT_NAME_INVALID;
dd89bb
dd89bb
	/* control block */
dd89bb
	if ((status = __ntapi_pty_alloc(&ctx)))
dd89bb
		return status;
dd89bb
dd89bb
	__ntapi_tt_guid_copy(
dd89bb
		&ctx->guid,
dd89bb
		&guid);
dd89bb
dd89bb
	ctx->access	= desired_access;
dd89bb
	ctx->flags	= obj_attr->obj_attr;
dd89bb
	ctx->share	= share_access;
dd89bb
	ctx->options	= open_options;
dd89bb
dd89bb
	/* pts */
47aaf2
	if (rpty) {
47aaf2
		ctx->hpty      = rpty->hpty;
47aaf2
		ctx->luid.high = rpty->luid.high;
47aaf2
		ctx->luid.low  = rpty->luid.low;
47aaf2
	} else {
47aaf2
		ctx->hpty      = obj_attr->root_dir;
dd89bb
	}
dd89bb
dd89bb
	if ((status = __ntapi_pty_connect(hport,ctx,iosb)))
dd89bb
		return status;
dd89bb
dd89bb
	*pty = ctx;
dd89bb
dd89bb
	return NT_STATUS_SUCCESS;
dd89bb
}
dd89bb
47aaf2
int32_t __stdcall __ntapi_pty_open(
47aaf2
	void *			hport,
47aaf2
	nt_pty **		pty,
47aaf2
	uint32_t		desired_access,
47aaf2
	nt_object_attributes*	obj_attr,
47aaf2
	nt_iosb *		iosb,
47aaf2
	uint32_t		share_access,
47aaf2
	uint32_t		open_options)
47aaf2
{
47aaf2
	return __ntapi_pty_open_impl(
47aaf2
		hport,pty,
47aaf2
		desired_access,
47aaf2
		obj_attr,iosb,
47aaf2
		share_access,
47aaf2
		open_options,
47aaf2
		(nt_pty *)obj_attr->root_dir);
47aaf2
}
47aaf2
47aaf2
int32_t __stdcall __ntapi_pty_open_pair(
47aaf2
	void *			hport,
47aaf2
	nt_pty **		pty,
47aaf2
	uint32_t		desired_access,
47aaf2
	nt_object_attributes*	obj_attr,
47aaf2
	nt_iosb *		iosb,
47aaf2
	uint32_t		share_access,
47aaf2
	uint32_t		open_options)
47aaf2
{
47aaf2
	return __ntapi_pty_open_impl(
47aaf2
		hport,pty,
47aaf2
		desired_access,
47aaf2
		obj_attr,iosb,
47aaf2
		share_access,
47aaf2
		open_options,
47aaf2
		0);
47aaf2
}
47aaf2
efc01e
int32_t	__stdcall __ntapi_pty_inherit(
efc01e
	__in	void *			hport,
efc01e
	__out	nt_pty **		pty,
efc01e
	__in 	nt_pty_client_info * 	client_info)
efc01e
{
efc01e
	int32_t 		status;
efc01e
	nt_iosb 		iosb;
efc01e
	nt_pty_inherit_info 	inherit;
efc01e
	nt_pty *		ctx;
efc01e
e62c29
	if ((status = __ntapi_pty_xquery(
efc01e
			hport,&iosb,
efc01e
			&inherit,sizeof(inherit),
e62c29
			NT_PTY_INHERIT_INFORMATION,
e62c29
			client_info)))
efc01e
		return status;
efc01e
efc01e
	/* control block */
efc01e
	if ((status = __ntapi_pty_alloc(&ctx)))
efc01e
		return status;
efc01e
efc01e
	__ntapi_tt_guid_copy(
efc01e
		&ctx->guid,
efc01e
		&inherit.guid);
efc01e
f4367d
	ctx->hpty	= inherit.hpty;
efc01e
	ctx->access	= inherit.access;
efc01e
	ctx->flags	= inherit.flags;
efc01e
	ctx->share	= inherit.share;
efc01e
	ctx->options	= inherit.options;
efc01e
efc01e
	ctx->luid.low 	= inherit.luid.low;
efc01e
	ctx->luid.high 	= inherit.luid.high;
efc01e
3a85e1
	if ((status = __ntapi_pty_connect(hport,ctx,&iosb)))
efc01e
		return status;
862d11
862d11
	if ((status = __ntapi_pty_set(
862d11
			ctx,&iosb,
862d11
			client_info,
862d11
			sizeof(*client_info),
862d11
			NT_PTY_CLIENT_INFORMATION))) {
862d11
		__ntapi_pty_free(ctx);
862d11
		return status;
862d11
	}
efc01e
efc01e
	*pty = ctx;
efc01e
efc01e
	return NT_STATUS_SUCCESS;
efc01e
}
efc01e
dd89bb
int32_t	__stdcall __ntapi_pty_reopen(
dd89bb
	__in	void *			hport,
dd89bb
	__in	nt_pty *		pty)
dd89bb
{
dd89bb
	return __ntapi_pty_connect(hport,pty,0);
dd89bb
}
dd89bb
dd89bb
int32_t __stdcall __ntapi_pty_close(nt_pty * pty)
dd89bb
{
dd89bb
	if (!pty || (pty->addr != pty))
dd89bb
		return NT_STATUS_INVALID_PARAMETER;
dd89bb
dd89bb
	__ntapi_pty_open_close(
dd89bb
		pty,&pty->iosb,NT_TTY_PTY_CLOSE);
dd89bb
dd89bb
	return __ntapi_pty_free(pty);
dd89bb
}
5ea20e
5ea20e
int32_t	__stdcall __ntapi_pty_inherit_runtime_ctty(
5ea20e
	__in	void *			hport,
5ea20e
     __in_out	nt_runtime_data *	rtdata)
5ea20e
{
5ea20e
	int32_t				status;
5ea20e
        nt_pty_client_info		client_info;
5ea20e
5ea20e
	if (rtdata->stdin_type == NT_FILE_TYPE_PTY) {
5ea20e
		client_info.any[0] = rtdata->ptyin[0];
5ea20e
		client_info.any[1] = rtdata->ptyin[1];
5ea20e
		client_info.any[2] = rtdata->ptyin[2];
5ea20e
		client_info.any[3] = rtdata->ptyin[3];
5ea20e
5ea20e
		if ((status = __ntapi_pty_inherit(
5ea20e
				hport,
5ea20e
				(nt_pty **)&rtdata->hstdin,
5ea20e
				&client_info)))
5ea20e
			return status;
5ea20e
	}
5ea20e
5ea20e
	if (rtdata->stdout_type == NT_FILE_TYPE_PTY) {
5ea20e
		if ((rtdata->stdin_type == NT_FILE_TYPE_PTY)
5ea20e
				&& (rtdata->ptyout[0] == rtdata->ptyin[0])
5ea20e
				&& (rtdata->ptyout[1] == rtdata->ptyin[1])
5ea20e
				&& (rtdata->ptyout[2] == rtdata->ptyin[2])
5ea20e
				&& (rtdata->ptyout[3] == rtdata->ptyin[3])) {
5ea20e
			rtdata->hstdout = rtdata->hstdin;
5ea20e
5ea20e
		} else {
5ea20e
			client_info.any[0] = rtdata->ptyout[0];
5ea20e
			client_info.any[1] = rtdata->ptyout[1];
5ea20e
			client_info.any[2] = rtdata->ptyout[2];
5ea20e
			client_info.any[3] = rtdata->ptyout[3];
5ea20e
5ea20e
			if ((status = __ntapi_pty_inherit(
5ea20e
					hport,
5ea20e
					(nt_pty **)&rtdata->hstdout,
5ea20e
					&client_info)))
5ea20e
				return status;
5ea20e
		}
5ea20e
	}
5ea20e
5ea20e
	if (rtdata->stderr_type == NT_FILE_TYPE_PTY) {
5ea20e
		if ((rtdata->stdin_type == NT_FILE_TYPE_PTY)
5ea20e
				&& (rtdata->ptyerr[0] == rtdata->ptyin[0])
5ea20e
				&& (rtdata->ptyerr[1] == rtdata->ptyin[1])
5ea20e
				&& (rtdata->ptyerr[2] == rtdata->ptyin[2])
5ea20e
				&& (rtdata->ptyerr[3] == rtdata->ptyin[3])) {
5ea20e
			rtdata->hstderr = rtdata->hstdin;
5ea20e
5ea20e
		} else if ((rtdata->stdout_type == NT_FILE_TYPE_PTY)
5ea20e
				&& (rtdata->ptyerr[0] == rtdata->ptyout[0])
5ea20e
				&& (rtdata->ptyerr[1] == rtdata->ptyout[1])
5ea20e
				&& (rtdata->ptyerr[2] == rtdata->ptyout[2])
5ea20e
				&& (rtdata->ptyerr[3] == rtdata->ptyout[3])) {
5ea20e
			rtdata->hstderr = rtdata->hstdout;
5ea20e
5ea20e
		} else {
5ea20e
			client_info.any[0] = rtdata->ptyerr[0];
5ea20e
			client_info.any[1] = rtdata->ptyerr[1];
5ea20e
			client_info.any[2] = rtdata->ptyerr[2];
5ea20e
			client_info.any[3] = rtdata->ptyerr[3];
5ea20e
5ea20e
			if ((status = __ntapi_pty_inherit(
5ea20e
					hport,
5ea20e
					(nt_pty **)&rtdata->hstderr,
5ea20e
					&client_info)))
5ea20e
				return status;
5ea20e
		}
5ea20e
	}
5ea20e
5ea20e
	/* hctty */
5ea20e
	if ((rtdata->stdin_type == NT_FILE_TYPE_PTY)
5ea20e
			&& (rtdata->ptyctl[0] == rtdata->ptyin[0])
5ea20e
			&& (rtdata->ptyctl[1] == rtdata->ptyin[1])
5ea20e
			&& (rtdata->ptyctl[2] == rtdata->ptyin[2])
5ea20e
			&& (rtdata->ptyctl[3] == rtdata->ptyin[3])) {
5ea20e
		rtdata->hctty = rtdata->hstdin;
5ea20e
5ea20e
	} else if ((rtdata->stdout_type == NT_FILE_TYPE_PTY)
5ea20e
			&& (rtdata->ptyctl[0] == rtdata->ptyout[0])
5ea20e
			&& (rtdata->ptyctl[1] == rtdata->ptyout[1])
5ea20e
			&& (rtdata->ptyctl[2] == rtdata->ptyout[2])
5ea20e
			&& (rtdata->ptyctl[3] == rtdata->ptyout[3])) {
5ea20e
		rtdata->hctty = rtdata->hstdout;
5ea20e
5ea20e
	} else if ((rtdata->stderr_type == NT_FILE_TYPE_PTY)
5ea20e
			&& (rtdata->ptyctl[0] == rtdata->ptyerr[0])
5ea20e
			&& (rtdata->ptyctl[1] == rtdata->ptyerr[1])
5ea20e
			&& (rtdata->ptyctl[2] == rtdata->ptyerr[2])
5ea20e
			&& (rtdata->ptyctl[3] == rtdata->ptyerr[3])) {
5ea20e
		rtdata->hctty = rtdata->hstderr;
5ea20e
5ea20e
	} else {
5ea20e
		client_info.any[0] = rtdata->ptyctl[0];
5ea20e
		client_info.any[1] = rtdata->ptyctl[1];
5ea20e
		client_info.any[2] = rtdata->ptyctl[2];
5ea20e
		client_info.any[3] = rtdata->ptyctl[3];
5ea20e
5ea20e
		if ((status = __ntapi_pty_inherit(
5ea20e
				hport,
5ea20e
				(nt_pty **)&rtdata->hctty,
5ea20e
				&client_info)))
5ea20e
			rtdata->hctty = 0;
5ea20e
	}
5ea20e
5ea20e
	return NT_STATUS_SUCCESS;
5ea20e
}