Blame src/sem/ntapi_sem_connect.c

9faf9a
/********************************************************/
9faf9a
/*  ntapi: Native API core library                      */
9faf9a
/*  Copyright (C) 2013--2017  Z. Gilboa                 */
9faf9a
/*  Released under GPLv2 and GPLv3; see COPYING.NTAPI.  */
9faf9a
/********************************************************/
9faf9a
9faf9a
#include <psxtypes/psxtypes.h>
9faf9a
#include <ntapi/nt_file.h>
9faf9a
#include <ntapi/nt_string.h>
9faf9a
#include <ntapi/nt_atomic.h>
9faf9a
#include <ntapi/nt_port.h>
9faf9a
#include <ntapi/nt_ipc.h>
9faf9a
#include <ntapi/nt_sem.h>
9faf9a
#include <ntapi/ntapi.h>
9faf9a
#include "ntapi_impl.h"
9faf9a
9faf9a
static const nt_guid	g_sempid    = NT_IPC_GUID_SEMPID;
9faf9a
static const wchar16_t	p_sempid[6] = NT_IPC_OBJDIR_PREFIX_SEMPID;
9faf9a
9faf9a
static int32_t __semctl_get_service_attr(
9faf9a
	nt_rtdata *		rtdata,
9faf9a
	nt_tty_service_info *	semctl)
9faf9a
{
9faf9a
	nt_iosb iosb;
9faf9a
9faf9a
	/* inherited runtime data? */
9faf9a
	if (rtdata->semctl_keys[0]) {
9faf9a
		semctl->attr.ver_major = 0;
9faf9a
		semctl->attr.ver_minor = 0;
9faf9a
		semctl->attr.options   = 0;
9faf9a
		semctl->attr.flags     = 0;
9faf9a
9faf9a
		semctl->attr.type    = rtdata->semctl_type;
9faf9a
		semctl->attr.subtype = rtdata->semctl_subtype;
9faf9a
9faf9a
		semctl->attr.keys.key[0] = rtdata->semctl_keys[0];
9faf9a
		semctl->attr.keys.key[1] = rtdata->semctl_keys[1];
9faf9a
		semctl->attr.keys.key[2] = rtdata->semctl_keys[2];
9faf9a
		semctl->attr.keys.key[3] = rtdata->semctl_keys[3];
9faf9a
		semctl->attr.keys.key[4] = rtdata->semctl_keys[4];
9faf9a
		semctl->attr.keys.key[5] = rtdata->semctl_keys[5];
9faf9a
9faf9a
		__ntapi->tt_guid_copy(
9faf9a
			&semctl->attr.guid,
9faf9a
			&rtdata->semctl_guid);
9faf9a
9faf9a
		return NT_STATUS_SUCCESS;
9faf9a
	}
9faf9a
9faf9a
	/* obtain service info */
9faf9a
	return __ntapi->tty_query_information_service(
9faf9a
		0,&iosb,
9faf9a
		semctl,&(nt_guid)NT_PORT_GUID_SEMCTL,
9faf9a
		0,0);
9faf9a
}
9faf9a
9faf9a
static int32_t __semctl_server_connect(
9faf9a
	nt_rtdata *		rtdata,
9faf9a
	nt_tty_service_info *	semctl)
9faf9a
{
9faf9a
	int32_t status;
9faf9a
9faf9a
	/* already cononected? */
9faf9a
	if (rtdata->hsemctl)
9faf9a
		return NT_STATUS_SUCCESS;
9faf9a
9faf9a
	/* connect */
9faf9a
	if ((status = __ntapi->ipc_connect_by_attr(
9faf9a
			&rtdata->hsemctl,
9faf9a
			&semctl->attr)))
9faf9a
		return status;
9faf9a
9faf9a
	/* update */
9faf9a
	rtdata->semctl_type    = semctl->attr.type;
9faf9a
	rtdata->semctl_subtype = semctl->attr.subtype;
9faf9a
9faf9a
	rtdata->semctl_keys[0] = semctl->attr.keys.key[0];
9faf9a
	rtdata->semctl_keys[1] = semctl->attr.keys.key[1];
9faf9a
	rtdata->semctl_keys[2] = semctl->attr.keys.key[2];
9faf9a
	rtdata->semctl_keys[3] = semctl->attr.keys.key[3];
9faf9a
	rtdata->semctl_keys[4] = semctl->attr.keys.key[4];
9faf9a
	rtdata->semctl_keys[5] = semctl->attr.keys.key[5];
9faf9a
9faf9a
	__ntapi->tt_guid_copy(
9faf9a
		&rtdata->semctl_guid,
9faf9a
		&semctl->attr.guid);
9faf9a
9faf9a
	return NT_STATUS_SUCCESS;
9faf9a
}
9faf9a
9faf9a
static int32_t __sempid_symlink_set(
9faf9a
	nt_rtdata *		rtdata,
9faf9a
	nt_tty_service_info *	semctl)
9faf9a
{
9faf9a
	int32_t			status;
9faf9a
	void *			hpiddir;
9faf9a
	nt_port_name		svcname;
9faf9a
	nt_unicode_string	str;
9faf9a
9faf9a
	if (rtdata->hsempid)
9faf9a
		return NT_STATUS_SUCCESS;
9faf9a
9faf9a
	if (!rtdata->hsempiddir) {
9faf9a
		if ((status = __ntapi->tt_open_ipc_object_directory(
9faf9a
				&hpiddir,
9faf9a
				NT_DIRECTORY_ALL_ACCESS,
9faf9a
				p_sempid,&g_sempid)))
9faf9a
			return status;
9faf9a
9faf9a
		if (at_locked_cas((intptr_t *)&rtdata->hsempiddir,0,(intptr_t)hpiddir))
9faf9a
			__ntapi->zw_close(hpiddir);
9faf9a
	}
9faf9a
9faf9a
	__ntapi->tt_port_name_from_attr(
9faf9a
		&svcname,&semctl->attr);
9faf9a
9faf9a
	str.strlen = (uint16_t)(size_t)(&(((nt_port_name *)0)->null_termination));
9faf9a
	str.maxlen = sizeof(nt_port_name);
9faf9a
	str.buffer = svcname.base_named_objects;
9faf9a
9faf9a
	return __ntapi->tt_create_ipc_object_directory_entry(
9faf9a
		&rtdata->hsempid,
9faf9a
		NT_SEC_STANDARD_RIGHTS_ALL,
9faf9a
		rtdata->hsempiddir,
9faf9a
		0,&str,
9faf9a
		pe_get_current_process_id());
9faf9a
9faf9a
}
9faf9a
9faf9a
static int32_t	__stdcall __sem_open(
9faf9a
	void *			hipc,
9faf9a
	nt_sem_info *		sem,
9faf9a
	uint32_t		access,
9faf9a
	nt_object_attributes *	oa,
9faf9a
	nt_iosb *		iosb,
9faf9a
	uint32_t		share,
9faf9a
	uint32_t		semslots,
9faf9a
	uint32_t		key,
9faf9a
	uint32_t		id,
9faf9a
	uint32_t		opcode)
9faf9a
{
9faf9a
	int32_t			status;
9faf9a
	nt_tty_port_msg		msg;
9faf9a
	nt_iosb			siosb;
9faf9a
	nt_tty_service_info	semctl;
9faf9a
	nt_runtime_data *	rtdata;
9faf9a
9faf9a
	/* init */
9faf9a
	rtdata = (__ntapi_internals())->rtdata;
9faf9a
9faf9a
	/* semctl service attributes */
9faf9a
	if (!rtdata->hsempid)
9faf9a
		if ((status = __semctl_get_service_attr(rtdata,&semctl)))
9faf9a
			return status;
9faf9a
9faf9a
	/* semctl server */
9faf9a
	if ((status = __semctl_server_connect(rtdata,&semctl)))
9faf9a
		return status;
9faf9a
9faf9a
	/* sempid symlink */
9faf9a
	if ((status = __sempid_symlink_set(rtdata,&semctl)))
9faf9a
		return status;
9faf9a
9faf9a
	/* hipc */
9faf9a
	if (!hipc && (opcode == NT_TTY_SEM_ALLOC))
9faf9a
		hipc = (__ntapi_internals())->rtdata->hsemctl;
9faf9a
9faf9a
	/* obtain sem info */
9faf9a
	__ntapi->tt_aligned_block_memset(
9faf9a
		&msg,0,sizeof(msg));
9faf9a
9faf9a
	if (!iosb)
9faf9a
		iosb = &siosb;
9faf9a
9faf9a
	msg.header.msg_type		= NT_LPC_NEW_MESSAGE;
9faf9a
	msg.header.data_size		= sizeof(nt_sem_info_msg) - sizeof(msg.header);
9faf9a
	msg.header.msg_size		= sizeof(msg);
9faf9a
	msg.ttyinfo.opcode		= opcode;
9faf9a
9faf9a
	msg.seminfo.semkey		= (int32_t)key;
9faf9a
	msg.seminfo.semid		= (int32_t)id;
9faf9a
	msg.seminfo.semslots		= semslots;
9faf9a
9faf9a
	msg.seminfo.ntattr		= oa->obj_attr;
9faf9a
	msg.seminfo.ntaccess		= access;
9faf9a
	msg.seminfo.ntshare		= share;
9faf9a
9faf9a
	if ((status = __ntapi->zw_request_wait_reply_port(hipc,&msg,&msg)))
9faf9a
		return status;
9faf9a
	else if (msg.ttyinfo.status)
9faf9a
		return msg.ttyinfo.status;
9faf9a
9faf9a
	iosb->info   = sizeof(msg.svcinfo);
9faf9a
	iosb->status = NT_STATUS_SUCCESS;
9faf9a
9faf9a
	/* new semaphore? */
9faf9a
	if (opcode == NT_TTY_SEM_ALLOC)
9faf9a
		if ((status = __ntapi->ipc_connect_by_attr(
9faf9a
				&hipc,&msg.svcinfo.attr)))
9faf9a
			return status;
9faf9a
9faf9a
	/* all done */
9faf9a
	__ntapi->tt_aligned_block_memset(
9faf9a
		(uintptr_t *)sem,
9faf9a
		0,sizeof(*sem));
9faf9a
9faf9a
	sem->semkey = msg.svcinfo.key;
9faf9a
	sem->semid  = msg.svcinfo.id;
9faf9a
9faf9a
	sem->hport = hipc;
9faf9a
9faf9a
	return NT_STATUS_SUCCESS;
9faf9a
}
9faf9a
9faf9a
9faf9a
int32_t	__ntapi_sem_create(
9faf9a
	__in	void *			hport,
9faf9a
	__out	nt_sem_info *		sem,
9faf9a
	__in	uint32_t		access,
9faf9a
	__in	nt_object_attributes *	oa,
9faf9a
	__out	nt_iosb *		iosb,
9faf9a
	__in	uint32_t		share,
9faf9a
	__in	uint32_t		nslots)
9faf9a
{
9faf9a
	uint32_t key;
9faf9a
9faf9a
	/* validate */
9faf9a
	if (!oa->root_dir)
9faf9a
		return NT_STATUS_DIRECTORY_SERVICE_REQUIRED;
9faf9a
9faf9a
	if (oa->obj_name && !oa->obj_name->strlen) {
9faf9a
		key = 0;
9faf9a
9faf9a
	} else if (oa->obj_name) {
9faf9a
		if (oa->obj_name->strlen != 8 * sizeof(wchar16_t))
9faf9a
			return NT_STATUS_OBJECT_NAME_INVALID;
9faf9a
9faf9a
		if (__ntapi->tt_hex_utf16_to_uint32(oa->obj_name->buffer,&key))
9faf9a
			return NT_STATUS_OBJECT_NAME_INVALID;
9faf9a
9faf9a
	} else {
9faf9a
		key = 0;
9faf9a
	}
9faf9a
9faf9a
	/* open semaphore */
9faf9a
	return __sem_open(
9faf9a
		hport,sem,access,
9faf9a
		oa,iosb,share,nslots,
9faf9a
		key,0,NT_TTY_SEM_ALLOC);
9faf9a
}
9faf9a
9faf9a
9faf9a
int32_t	__stdcall __ntapi_sem_open(
9faf9a
	__in	void *			hport,
9faf9a
	__out	nt_sem_info *		sem,
9faf9a
	__in	uint32_t		access,
9faf9a
	__in	nt_object_attributes *	oa,
9faf9a
	__out	nt_iosb *		iosb,
9faf9a
	__in	uint32_t		share,
9faf9a
	__in	uint32_t		nslots)
9faf9a
{
edb085
	int32_t			status;
edb085
	uint32_t		key;
edb085
	uint32_t		id;
edb085
	void *			hsymlink;
edb085
	nt_oa			ipcoa;
edb085
	void *			hipc;
edb085
	nt_rtdata *		rtdata;
edb085
	nt_tty_service_info	semctl;
edb085
edb085
	/* init */
edb085
	rtdata = (__ntapi_internals())->rtdata;
9faf9a
9faf9a
	/* validate */
9faf9a
	if (!oa->root_dir)
9faf9a
		return NT_STATUS_DIRECTORY_SERVICE_REQUIRED;
9faf9a
9faf9a
	if (!oa->obj_name)
9faf9a
		return NT_STATUS_INVALID_PARAMETER;
9faf9a
9faf9a
	if (oa->obj_name->strlen != 8 * sizeof(wchar16_t))
9faf9a
		return NT_STATUS_OBJECT_NAME_INVALID;
9faf9a
9faf9a
	if (__ntapi->tt_hex_utf16_to_uint32(oa->obj_name->buffer,&key))
9faf9a
		return NT_STATUS_OBJECT_NAME_INVALID;
9faf9a
9faf9a
	/* open symlink */
9faf9a
	ipcoa.len      = sizeof(ipcoa);
9faf9a
	ipcoa.root_dir = oa->root_dir;
9faf9a
	ipcoa.obj_name = oa->obj_name;
9faf9a
	ipcoa.obj_attr = 0;
9faf9a
	ipcoa.sec_desc = oa->sec_desc;
9faf9a
	ipcoa.sec_qos  = oa->sec_qos;
9faf9a
9faf9a
	status = __ntapi->zw_open_symbolic_link_object(
9faf9a
		&hsymlink,
9faf9a
		NT_SEC_STANDARD_RIGHTS_READ | NT_GENERIC_READ,
9faf9a
		&ipcoa);
9faf9a
9faf9a
	switch (status) {
9faf9a
		case NT_STATUS_SUCCESS:
9faf9a
			break;
9faf9a
9faf9a
		case NT_STATUS_OBJECT_NAME_NOT_FOUND:
9faf9a
		case NT_STATUS_OBJECT_PATH_NOT_FOUND:
9faf9a
			if (oa->obj_attr & NT_OBJ_OPENIF)
9faf9a
				return __sem_open(
9faf9a
					hport,sem,access,
9faf9a
					oa,iosb,share,nslots,
9faf9a
					key,0,NT_TTY_SEM_ALLOC);
9faf9a
			else
9faf9a
				return status;
9faf9a
9faf9a
		default:
9faf9a
			return status;
9faf9a
	}
9faf9a
edb085
	/* semctl service attributes */
edb085
	if (!rtdata->hsempid)
edb085
		if ((status = __semctl_get_service_attr(rtdata,&semctl)))
edb085
			return status;
edb085
edb085
	/* semctl server */
edb085
	if ((status = __semctl_server_connect(rtdata,&semctl)))
edb085
		return status;
edb085
edb085
	/* sempid symlink */
edb085
	if ((status = __sempid_symlink_set(rtdata,&semctl)))
edb085
		return status;
edb085
9faf9a
	/* ipc connect */
9faf9a
	status = __ntapi->ipc_connect_by_symlink(
9faf9a
		&hipc,hsymlink);
9faf9a
9faf9a
	__ntapi->zw_close(
9faf9a
		hsymlink);
9faf9a
9faf9a
	if (status)
9faf9a
		return status;
9faf9a
9faf9a
	/* open by id? */
9faf9a
	if (oa->obj_attr & NT_OBJ_OPENLINK) {
9faf9a
		id  = key;
9faf9a
		key = 0;
9faf9a
	} else {
9faf9a
		id  = 0;
9faf9a
	}
9faf9a
9faf9a
	return __sem_open(
9faf9a
		hipc,sem,access,
9faf9a
		oa,iosb,share,nslots,
9faf9a
		key,id,NT_TTY_SEM_OPEN);
9faf9a
}