Blame src/afl/ntapi_afl_connect.c

6a4793
/********************************************************/
6a4793
/*  ntapi: Native API core library                      */
6a4793
/*  Copyright (C) 2013--2017  Z. Gilboa                 */
6a4793
/*  Released under GPLv2 and GPLv3; see COPYING.NTAPI.  */
6a4793
/********************************************************/
6a4793
6a4793
#include <psxtypes/psxtypes.h>
6a4793
#include <ntapi/nt_file.h>
6a4793
#include <ntapi/nt_string.h>
6a4793
#include <ntapi/nt_atomic.h>
6a4793
#include <ntapi/nt_port.h>
6a4793
#include <ntapi/nt_ipc.h>
6a4793
#include <ntapi/nt_afl.h>
6a4793
#include <ntapi/ntapi.h>
6a4793
#include "ntapi_impl.h"
6a4793
6a4793
static const nt_guid	g_aflpid    = NT_IPC_GUID_AFLPID;
6a4793
static const wchar16_t	p_aflpid[6] = NT_IPC_OBJDIR_PREFIX_AFLPID;
6a4793
6a4793
static int32_t __aflctl_get_service_attr(
6a4793
	nt_rtdata *		rtdata,
6a4793
	nt_tty_service_info *	aflctl)
6a4793
{
6a4793
	nt_iosb iosb;
6a4793
6a4793
	/* inherited runtime data? */
6a4793
	if (rtdata->aflctl_keys[0]) {
6a4793
		aflctl->attr.ver_major = 0;
6a4793
		aflctl->attr.ver_minor = 0;
6a4793
		aflctl->attr.options   = 0;
6a4793
		aflctl->attr.flags     = 0;
6a4793
6a4793
		aflctl->attr.type    = rtdata->aflctl_type;
6a4793
		aflctl->attr.subtype = rtdata->aflctl_subtype;
6a4793
6a4793
		aflctl->attr.keys.key[0] = rtdata->aflctl_keys[0];
6a4793
		aflctl->attr.keys.key[1] = rtdata->aflctl_keys[1];
6a4793
		aflctl->attr.keys.key[2] = rtdata->aflctl_keys[2];
6a4793
		aflctl->attr.keys.key[3] = rtdata->aflctl_keys[3];
6a4793
		aflctl->attr.keys.key[4] = rtdata->aflctl_keys[4];
6a4793
		aflctl->attr.keys.key[5] = rtdata->aflctl_keys[5];
6a4793
6a4793
		__ntapi->tt_guid_copy(
6a4793
			&aflctl->attr.guid,
6a4793
			&rtdata->aflctl_guid);
6a4793
6a4793
		return NT_STATUS_SUCCESS;
6a4793
	}
6a4793
6a4793
	/* obtain service info */
6a4793
	return __ntapi->tty_query_information_service(
6a4793
		0,&iosb,aflctl,
6a4793
		&(nt_guid)NT_PORT_GUID_AFLCTL,
6a4793
		0,0);
6a4793
}
6a4793
6a4793
static int32_t __aflctl_server_connect(
6a4793
	nt_rtdata *		rtdata,
6a4793
	nt_tty_service_info *	aflctl)
6a4793
{
6a4793
	int32_t status;
6a4793
6a4793
	/* already cononected? */
6a4793
	if (rtdata->haflctl)
6a4793
		return NT_STATUS_SUCCESS;
6a4793
6a4793
	/* connect */
6a4793
	if ((status = __ntapi->ipc_connect_by_attr(
6a4793
			&rtdata->haflctl,
6a4793
			&aflctl->attr)))
6a4793
		return status;
6a4793
6a4793
	/* update */
6a4793
	rtdata->aflctl_type    = aflctl->attr.type;
6a4793
	rtdata->aflctl_subtype = aflctl->attr.subtype;
6a4793
6a4793
	rtdata->aflctl_keys[0] = aflctl->attr.keys.key[0];
6a4793
	rtdata->aflctl_keys[1] = aflctl->attr.keys.key[1];
6a4793
	rtdata->aflctl_keys[2] = aflctl->attr.keys.key[2];
6a4793
	rtdata->aflctl_keys[3] = aflctl->attr.keys.key[3];
6a4793
	rtdata->aflctl_keys[4] = aflctl->attr.keys.key[4];
6a4793
	rtdata->aflctl_keys[5] = aflctl->attr.keys.key[5];
6a4793
6a4793
	__ntapi->tt_guid_copy(
6a4793
		&rtdata->aflctl_guid,
6a4793
		&aflctl->attr.guid);
6a4793
6a4793
	return NT_STATUS_SUCCESS;
6a4793
}
6a4793
6a4793
static int32_t __aflpid_symlink_set(
6a4793
	nt_rtdata *		rtdata,
6a4793
	nt_tty_service_info *	aflctl)
6a4793
{
6a4793
	int32_t			status;
6a4793
	void *			hpiddir;
6a4793
	nt_port_name		svcname;
6a4793
	nt_unicode_string	str;
6a4793
6a4793
	if (rtdata->haflpid)
6a4793
		return NT_STATUS_SUCCESS;
6a4793
6a4793
	if (!rtdata->haflpiddir) {
6a4793
		if ((status = __ntapi->tt_open_ipc_object_directory(
6a4793
				&hpiddir,
6a4793
				NT_SEC_READ_CONTROL
6a4793
					| NT_DIRECTORY_QUERY
6a4793
					| NT_DIRECTORY_TRAVERSE
6a4793
					| NT_DIRECTORY_CREATE_OBJECT
6a4793
					| NT_DIRECTORY_CREATE_SUBDIRECTORY,
6a4793
				p_aflpid,&g_aflpid)))
6a4793
			return status;
6a4793
6a4793
		if (at_locked_cas((intptr_t *)&rtdata->haflpiddir,0,(intptr_t)hpiddir))
6a4793
			__ntapi->zw_close(hpiddir);
6a4793
	}
6a4793
6a4793
	__ntapi->tt_port_name_from_attr(
6a4793
		&svcname,&aflctl->attr);
6a4793
6a4793
	str.strlen = (uint16_t)(__offsetof(nt_port_name,null_termination));
6a4793
	str.maxlen = sizeof(nt_port_name);
6a4793
	str.buffer = svcname.base_named_objects;
6a4793
6a4793
	return __ntapi->tt_create_ipc_object_directory_entry(
6a4793
		&rtdata->haflpid,
6a4793
		NT_SEC_STANDARD_RIGHTS_ALL,
6a4793
		rtdata->haflpiddir,
6a4793
		0,&str,
6a4793
		pe_get_current_process_id());
6a4793
6a4793
}
6a4793
6a4793
static int32_t	__stdcall __afl_open(
6a4793
	void *			hipc,
6a4793
	nt_afl_info *		afl,
6a4793
	nt_iosb *		iosb,
6a4793
	nt_guid *		afldev,
6a4793
	uint32_t		opcode)
6a4793
{
6a4793
	int32_t			status;
6a4793
	nt_tty_port_msg		msg;
6a4793
	nt_iosb			siosb;
6a4793
	nt_tty_service_info	aflctl;
6a4793
	nt_runtime_data *	rtdata;
6a4793
6a4793
	/* init */
6a4793
	rtdata = (__ntapi_internals())->rtdata;
6a4793
6a4793
	/* aflctl service attributes */
6a4793
	if (!rtdata->haflpid)
6a4793
		if ((status = __aflctl_get_service_attr(rtdata,&aflctl)))
6a4793
			return status;
6a4793
6a4793
	/* aflctl server */
6a4793
	if ((status = __aflctl_server_connect(rtdata,&aflctl)))
6a4793
		return status;
6a4793
6a4793
	/* aflpid symlink */
6a4793
	if ((status = __aflpid_symlink_set(rtdata,&aflctl)))
6a4793
		return status;
6a4793
6a4793
	/* hipc */
6a4793
	if (!hipc && (opcode == NT_TTY_AFL_ALLOC))
6a4793
		hipc = (__ntapi_internals())->rtdata->haflctl;
6a4793
6a4793
	/* obtain afl info */
6a4793
	__ntapi->tt_aligned_block_memset(
6a4793
		&msg,0,sizeof(msg));
6a4793
6a4793
	if (!iosb)
6a4793
		iosb = &siosb;
6a4793
6a4793
	msg.header.msg_type		= NT_LPC_NEW_MESSAGE;
6a4793
	msg.header.data_size		= sizeof(nt_afl_info_msg) - sizeof(msg.header);
6a4793
	msg.header.msg_size		= sizeof(msg);
6a4793
	msg.ttyinfo.opcode		= opcode;
6a4793
6a4793
	__ntapi->tt_guid_copy(
6a4793
		&msg.aflinfo.afldev,
6a4793
		afldev);
6a4793
6a4793
	/* todo: device guid */
6a4793
6a4793
	if ((status = __ntapi->zw_request_wait_reply_port(hipc,&msg,&msg)))
6a4793
		return status;
6a4793
	else if (msg.ttyinfo.status)
6a4793
		return msg.ttyinfo.status;
6a4793
6a4793
	iosb->info   = sizeof(msg.svcinfo);
6a4793
	iosb->status = NT_STATUS_SUCCESS;
6a4793
6a4793
	/* new afl node? */
6a4793
	if (opcode == NT_TTY_AFL_ALLOC)
6a4793
		if ((status = __ntapi->ipc_connect_by_attr(
6a4793
				&hipc,&msg.svcinfo.attr)))
6a4793
			return status;
6a4793
6a4793
	/* all done */
6a4793
	__ntapi->tt_aligned_block_memset(
6a4793
		(uintptr_t *)afl,
6a4793
		0,sizeof(*afl));
6a4793
6a4793
	afl->hport = hipc;
6a4793
6a4793
	__ntapi->tt_guid_copy(
6a4793
		&afl->afldev,
6a4793
		afldev);
6a4793
6a4793
	return NT_STATUS_SUCCESS;
6a4793
}
6a4793
6a4793
6a4793
int32_t	__ntapi_afl_create(
6a4793
	__in	void *			hport,
6a4793
	__out	nt_afl_info *		afl,
6a4793
	__in	nt_oa *			oa,
6a4793
	__out	nt_iosb *		iosb)
6a4793
{
6a4793
	nt_guid afldev;
6a4793
6a4793
	/* validate */
6a4793
	if (!oa->root_dir)
6a4793
		return NT_STATUS_DIRECTORY_SERVICE_REQUIRED;
6a4793
6a4793
	if (!oa->obj_name)
6a4793
		return NT_STATUS_INVALID_PARAMETER;
6a4793
6a4793
	if (oa->obj_name->strlen != sizeof(nt_guid_str_utf16))
6a4793
		return NT_STATUS_OBJECT_NAME_INVALID;
6a4793
6a4793
	if (__ntapi->tt_string_to_guid_utf16(
6a4793
			(nt_guid_str_utf16 *)oa->obj_name->buffer,
6a4793
			&afldev))
6a4793
		return NT_STATUS_OBJECT_NAME_INVALID;
6a4793
6a4793
	/* open afldev */
6a4793
	return __afl_open(
6a4793
		hport,afl,iosb,
6a4793
		&afldev,
6a4793
		NT_TTY_AFL_ALLOC);
6a4793
}
6a4793
6a4793
6a4793
int32_t	__stdcall __ntapi_afl_open(
6a4793
	__in	void *			hport,
6a4793
	__out	nt_afl_info *		afl,
6a4793
	__in	nt_oa *			oa,
6a4793
	__out	nt_iosb *		iosb)
6a4793
{
6a4793
	int32_t			status;
6a4793
	nt_guid			afldev;
6a4793
	void *			hsymlink;
6a4793
	nt_oa			ipcoa;
6a4793
	void *			hipc;
6a4793
	nt_rtdata *		rtdata;
6a4793
	nt_tty_service_info	aflctl;
6a4793
6a4793
	/* init */
6a4793
	rtdata = (__ntapi_internals())->rtdata;
6a4793
6a4793
	/* validate */
6a4793
	if (!oa->root_dir)
6a4793
		return NT_STATUS_DIRECTORY_SERVICE_REQUIRED;
6a4793
6a4793
	if (!oa->obj_name)
6a4793
		return NT_STATUS_INVALID_PARAMETER;
6a4793
6a4793
	if (oa->obj_name->strlen != sizeof(nt_guid_str_utf16))
6a4793
		return NT_STATUS_OBJECT_NAME_INVALID;
6a4793
6a4793
	if (__ntapi->tt_string_to_guid_utf16(
6a4793
			(nt_guid_str_utf16 *)oa->obj_name->buffer,
6a4793
			&afldev))
6a4793
		return NT_STATUS_OBJECT_NAME_INVALID;
6a4793
6a4793
	/* open symlink */
6a4793
	ipcoa.len      = sizeof(ipcoa);
6a4793
	ipcoa.root_dir = oa->root_dir;
6a4793
	ipcoa.obj_name = oa->obj_name;
6a4793
	ipcoa.obj_attr = 0;
6a4793
	ipcoa.sec_desc = oa->sec_desc;
6a4793
	ipcoa.sec_qos  = oa->sec_qos;
6a4793
6a4793
	status = __ntapi->zw_open_symbolic_link_object(
6a4793
		&hsymlink,
6a4793
		NT_SYMBOLIC_LINK_QUERY,
6a4793
		&ipcoa);
6a4793
6a4793
	switch (status) {
6a4793
		case NT_STATUS_SUCCESS:
6a4793
			break;
6a4793
6a4793
		case NT_STATUS_OBJECT_NAME_NOT_FOUND:
6a4793
		case NT_STATUS_OBJECT_PATH_NOT_FOUND:
6a4793
			if (oa->obj_attr & NT_OBJ_OPENIF)
6a4793
				return __afl_open(
6a4793
					hport,afl,iosb,
6a4793
					&afldev,
6a4793
					NT_TTY_AFL_ALLOC);
6a4793
			else
6a4793
				return status;
6a4793
6a4793
		default:
6a4793
			return status;
6a4793
	}
6a4793
6a4793
	/* aflctl service attributes */
6a4793
	if (!rtdata->haflpid)
6a4793
		if ((status = __aflctl_get_service_attr(rtdata,&aflctl)))
6a4793
			return status;
6a4793
6a4793
	/* aflctl server */
6a4793
	if ((status = __aflctl_server_connect(rtdata,&aflctl)))
6a4793
		return status;
6a4793
6a4793
	/* aflpid symlink */
6a4793
	if ((status = __aflpid_symlink_set(rtdata,&aflctl)))
6a4793
		return status;
6a4793
6a4793
	/* ipc connect */
6a4793
	status = __ntapi->ipc_connect_by_symlink(
6a4793
		&hipc,hsymlink);
6a4793
6a4793
	__ntapi->zw_close(
6a4793
		hsymlink);
6a4793
6a4793
	if (status)
6a4793
		return status;
6a4793
6a4793
	return __afl_open(
6a4793
		hipc,afl,iosb,
6a4793
		&afldev,
6a4793
		NT_TTY_AFL_OPEN);
6a4793
}