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