/********************************************************/
/* 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/nt_object.h>
#include <ntapi/nt_guid.h>
#include <ntapi/nt_string.h>
#include <ntapi/nt_acl.h>
#include "ntapi_impl.h"
#define __SID_SYSTEM {1,1,{{0,0,0,0,0,5}},{18}}
#define __SID_OWNER_RIGHTS {1,1,{{0,0,0,0,0,3}},{4}}
#define __SID_AUTHENTICATED_USERS {1,1,{{0,0,0,0,0,5}},{11}}
static const nt_sid sid_system = __SID_SYSTEM;
static const nt_sid sid_owner_rights = __SID_OWNER_RIGHTS;
static const nt_sid sid_auth_users = __SID_AUTHENTICATED_USERS;
typedef ntapi_zw_open_directory_object objdir_open_fn;
static void __tt_guid_to_hex_utf16(
__in const nt_guid * guid,
__out wchar16_t * hex_str)
{
uint16_t key;
__ntapi_tt_uint32_to_hex_utf16(
guid->data1,&hex_str[0]);
__ntapi_tt_uint16_to_hex_utf16(
guid->data2,&hex_str[9]);
__ntapi_tt_uint16_to_hex_utf16(
guid->data3,&hex_str[14]);
key = guid->data4[0] * 0x100 + guid->data4[1];
__ntapi_tt_uint16_to_hex_utf16(
key,&hex_str[19]);
key = guid->data4[2] * 0x100 + guid->data4[3];
__ntapi_tt_uint16_to_hex_utf16(
key,&hex_str[24]);
key = guid->data4[4] * 0x100 + guid->data4[5];
__ntapi_tt_uint16_to_hex_utf16(
key,&hex_str[28]);
key = guid->data4[6] * 0x100 + guid->data4[7];
__ntapi_tt_uint16_to_hex_utf16(
key,&hex_str[32]);
hex_str[8] = '-';
hex_str[13] = '-';
hex_str[18] = '-';
hex_str[23] = '-';
}
static nt_access_allowed_ace * __ipc_ace_init(
nt_access_allowed_ace * ace,
uint32_t mask,
const nt_sid * sid)
{
ace->mask = mask;
ace->header.ace_type = NT_ACE_TYPE_ACCESS_ALLOWED;
ace->header.ace_flags = 0;
ace->header.ace_size = sizeof(uint32_t) * sid->sub_authority_count
+ __offsetof(nt_access_allowed_ace,sid_start)
+ __offsetof(nt_sid,sub_authority);
__ntapi->tt_sid_copy(
(nt_sid *)&ace->sid_start,
sid);
return (nt_access_allowed_ace *)((size_t)ace + ace->header.ace_size);
}
static void __ipc_sd_init(nt_sd_common_buffer * sd, int fdir)
{
nt_access_allowed_ace * ace;
uint32_t mask_system;
uint32_t mask_owner;
uint32_t mask_other;
/* access mask */
if (fdir) {
mask_system = NT_SEC_READ_CONTROL
| NT_DIRECTORY_QUERY
| NT_DIRECTORY_TRAVERSE
| NT_DIRECTORY_CREATE_OBJECT
| NT_DIRECTORY_CREATE_SUBDIRECTORY;
mask_owner = NT_DIRECTORY_ALL_ACCESS;
mask_other = mask_system;
} else {
mask_system = NT_SYMBOLIC_LINK_ALL_ACCESS;
mask_owner = NT_SYMBOLIC_LINK_ALL_ACCESS;
mask_other = NT_SYMBOLIC_LINK_ALL_ACCESS;
}
/* sd header */
sd->sd.revision = 1;
sd->sd.sbz_1st = 0;
sd->sd.control = NT_SE_SELF_RELATIVE | NT_SE_DACL_PRESENT;
sd->sd.offset_owner = __offsetof(nt_sd_common_buffer,owner);
sd->sd.offset_group = 0;
sd->sd.offset_dacl = __offsetof(nt_sd_common_buffer,dacl);
sd->sd.offset_sacl = 0;
/* owner sid */
__ntapi->tt_sid_copy(
(nt_sid *)&sd->owner,
__ntapi_internals()->user);
/* ace's for LOCAL_SYSTEM, AUTHENTICATED_USERS, and process token user */
ace = (nt_access_allowed_ace *)&sd->buffer;
ace = __ipc_ace_init(ace,mask_system,&sid_system);
ace = __ipc_ace_init(ace,mask_other,&sid_auth_users);
ace = __ipc_ace_init(ace,mask_owner,&sid_owner_rights);
ace = __ipc_ace_init(ace,mask_owner,(nt_sid *)&sd->owner);
sd->dacl.acl_revision = 0x02;
sd->dacl.sbz_1st = 0;
sd->dacl.acl_size = (uint16_t)((char *)ace - (char *)&sd->dacl);
sd->dacl.ace_count = 3;
sd->dacl.sbz_2nd = 0;
}
static int32_t __stdcall __tt_create_ipc_object_directory(
__out void ** hdir,
__in uint32_t desired_access,
__in const wchar16_t prefix[6],
__in const nt_guid * guid)
{
int32_t status;
nt_ipc_objdir_name objdir_name;
nt_unicode_string name;
nt_sd_common_buffer sd;
nt_oa oa;
nt_sqos sqos = {
sizeof(sqos),
NT_SECURITY_IMPERSONATION,
NT_SECURITY_TRACKING_DYNAMIC,
1};
__ipc_sd_init(&sd,1);
__ntapi->tt_generic_memcpy(
objdir_name.base_named_objects,
(wchar16_t[])__NT_BASED_NAMED_OBJECTS,
sizeof(objdir_name.base_named_objects));
__ntapi->tt_memcpy_utf16(
objdir_name.prefix,
prefix,
sizeof(objdir_name.prefix));
__tt_guid_to_hex_utf16(
guid,objdir_name.guid);
objdir_name.backslash = '\\';
objdir_name.uscore = '_';
name.strlen = sizeof(objdir_name);
name.maxlen = 0;
name.buffer = objdir_name.base_named_objects;
oa.len = sizeof(oa);
oa.root_dir = 0;
oa.obj_name = &name;
oa.obj_attr = NT_OBJ_INHERIT
| NT_OBJ_OPENIF
| NT_OBJ_CASE_INSENSITIVE;
oa.sec_desc = &sd.sd;
oa.sec_qos = &sqos;
status = __ntapi->zw_create_directory_object(
hdir,desired_access,&oa);
return (status == NT_STATUS_OBJECT_NAME_EXISTS)
? NT_STATUS_SUCCESS
: status;
}
static int32_t __stdcall __tt_create_keyed_object_directory(
__out void ** hdir,
__in uint32_t desired_access,
__in void * hparent,
__in uint32_t key,
__in objdir_open_fn * openfn)
{
wchar16_t keystr[8];
nt_unicode_string name;
nt_sd_common_buffer sd;
nt_oa oa;
nt_sqos sqos = {
sizeof(sqos),
NT_SECURITY_IMPERSONATION,
NT_SECURITY_TRACKING_DYNAMIC,
1};
__ipc_sd_init(&sd,1);
__ntapi->tt_uint32_to_hex_utf16(
key,keystr);
name.strlen = sizeof(keystr);
name.maxlen = 0;
name.buffer = keystr;
oa.len = sizeof(oa);
oa.root_dir = hparent;
oa.obj_name = &name;
oa.obj_attr = NT_OBJ_INHERIT;
oa.sec_desc = &sd.sd;
oa.sec_qos = &sqos;
return openfn(hdir,desired_access,&oa);
}
static int32_t __stdcall __tt_create_object_directory_entry(
__out void ** hentry,
__in uint32_t desired_access,
__in void * hdir,
__in void * htarget,
__in nt_unicode_string * target_name,
__in uint32_t key)
{
int32_t status;
nt_oa oa;
nt_unicode_string name;
nt_sd_common_buffer sd;
wchar16_t keystr[8];
uintptr_t buffer[2048/sizeof(uintptr_t)];
nt_sqos sqos = {
sizeof(sqos),
NT_SECURITY_IMPERSONATION,
NT_SECURITY_TRACKING_DYNAMIC,
1};
if (!target_name) {
if ((status = __ntapi->zw_query_object(
htarget,
NT_OBJECT_NAME_INFORMATION,
buffer,sizeof(buffer),0)))
return status;
target_name = (nt_unicode_string *)buffer;
}
__ipc_sd_init(&sd,0);
__ntapi->tt_uint32_to_hex_utf16(key,keystr);
name.strlen = sizeof(keystr);
name.maxlen = 0;
name.buffer = keystr;
oa.len = sizeof(oa);
oa.root_dir = hdir;
oa.obj_name = &name;
oa.obj_attr = 0;
oa.sec_desc = &sd.sd;
oa.sec_qos = &sqos;
return __ntapi->zw_create_symbolic_link_object(
hentry,
desired_access,
&oa,target_name);
}
int32_t __stdcall __ntapi_tt_open_ipc_object_directory(
__out void ** hdir,
__in uint32_t desired_access,
__in const wchar16_t prefix[6],
__in const nt_guid * guid)
{
return __tt_create_ipc_object_directory(
hdir,desired_access,
prefix,guid);
}
int32_t __stdcall __ntapi_tt_create_ipc_object_directory_entry(
__out void ** hentry,
__in uint32_t desired_access,
__in void * hdir,
__in void * htarget,
__in nt_unicode_string * target_name,
__in uint32_t key)
{
return __tt_create_object_directory_entry(
hentry,desired_access,
hdir,htarget,target_name,key);
}
int32_t __stdcall __ntapi_tt_open_dev_object_directory(
__out void ** hdir,
__in uint32_t desired_access,
__in const wchar16_t prefix[6],
__in const nt_guid * ipc_guid)
{
return __tt_create_ipc_object_directory(
hdir,desired_access,
prefix,ipc_guid);
}
int32_t __stdcall __ntapi_tt_create_dev_object_directory_entry(
__out void ** hentry,
__in uint32_t desired_access,
__in void * hdir,
__in void * htarget,
__in nt_unicode_string * target_name,
__in const nt_guid * dev_guid)
{
int32_t status;
nt_oa oa;
nt_unicode_string name;
nt_sd_common_buffer sd;
nt_guid_str_utf16 guidstr;
uintptr_t buffer[2048/sizeof(uintptr_t)];
nt_sqos sqos = {
sizeof(sqos),
NT_SECURITY_IMPERSONATION,
NT_SECURITY_TRACKING_DYNAMIC,
1};
if (!target_name) {
if ((status = __ntapi->zw_query_object(
htarget,
NT_OBJECT_NAME_INFORMATION,
buffer,sizeof(buffer),0)))
return status;
target_name = (nt_unicode_string *)buffer;
}
__ipc_sd_init(&sd,0);
__ntapi->tt_guid_to_string_utf16(dev_guid,&guidstr);
name.strlen = sizeof(guidstr);
name.maxlen = 0;
name.buffer = &guidstr.lbrace;
oa.len = sizeof(oa);
oa.root_dir = hdir;
oa.obj_name = &name;
oa.obj_attr = 0;
oa.sec_desc = &sd.sd;
oa.sec_qos = &sqos;
return __ntapi->zw_create_symbolic_link_object(
hentry,
desired_access,
&oa,target_name);
}
int32_t __stdcall __ntapi_tt_create_keyed_object_directory(
__out void ** hdir,
__in uint32_t desired_access,
__in void * hparent,
__in uint32_t key)
{
return __tt_create_keyed_object_directory(
hdir,desired_access,
hparent,key,
__ntapi->zw_create_directory_object);
}
int32_t __stdcall __ntapi_tt_open_keyed_object_directory(
__out void ** hdir,
__in uint32_t desired_access,
__in void * hparent,
__in uint32_t key)
{
return __tt_create_keyed_object_directory(
hdir,desired_access,
hparent,key,
__ntapi->zw_open_directory_object);
}
int32_t __stdcall __ntapi_tt_create_keyed_object_directory_entry(
__out void ** hentry,
__in uint32_t desired_access,
__in void * hdir,
__in void * htarget,
__in nt_unicode_string * target_name,
__in uint32_t key)
{
return __tt_create_object_directory_entry(
hentry,desired_access,
hdir,htarget,target_name,key);
}
int32_t __stdcall __ntapi_tt_keyed_object_to_key(
__in void * hentry,
__out uint32_t * key,
__out void * buffer,
__in size_t buflen)
{
int32_t status;
wchar16_t * pidname;
nt_unicode_string * dirname;
if ((status = __ntapi->zw_query_object(
hentry,
NT_OBJECT_NAME_INFORMATION,
buffer,buflen,
&(uint32_t){0})))
return status;
dirname = (nt_unicode_string *)buffer;
pidname = dirname->buffer;
if (dirname->strlen <= 8 * sizeof(wchar16_t))
return NT_STATUS_INTERNAL_ERROR;
pidname += dirname->strlen / sizeof(wchar16_t);
pidname -= 8;
if (pidname[-1] != '\\')
return NT_STATUS_INVALID_PARAMETER;
return __ntapi->tt_hex_utf16_to_uint32(
pidname,key);
}