/********************************************************/ /* ntapi: Native API core library */ /* Copyright (C) 2013--2021 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_msqpid = NT_IPC_GUID_MSQPID; static const wchar16_t p_msqpid[6] = NT_IPC_OBJDIR_PREFIX_MSQPID; static int32_t __msqctl_get_service_attr( nt_rtdata * rtdata, nt_tty_service_info * msqctl) { nt_iosb iosb; /* inherited runtime data? */ if (rtdata->msqctl_keys[0]) { msqctl->attr.ver_major = 0; msqctl->attr.ver_minor = 0; msqctl->attr.options = 0; msqctl->attr.flags = 0; msqctl->attr.type = rtdata->msqctl_type; msqctl->attr.subtype = rtdata->msqctl_subtype; msqctl->attr.keys.key[0] = rtdata->msqctl_keys[0]; msqctl->attr.keys.key[1] = rtdata->msqctl_keys[1]; msqctl->attr.keys.key[2] = rtdata->msqctl_keys[2]; msqctl->attr.keys.key[3] = rtdata->msqctl_keys[3]; msqctl->attr.keys.key[4] = rtdata->msqctl_keys[4]; msqctl->attr.keys.key[5] = rtdata->msqctl_keys[5]; __ntapi->tt_guid_copy( &msqctl->attr.guid, &rtdata->msqctl_guid); return NT_STATUS_SUCCESS; } /* obtain service info */ return __ntapi->tty_query_information_service( 0,&iosb,msqctl, &(nt_guid)NT_PORT_GUID_MSQCTL, 0,0); } static int32_t __msqctl_server_connect( nt_rtdata * rtdata, nt_tty_service_info * msqctl) { int32_t status; /* already cononected? */ if (rtdata->hmsqctl) return NT_STATUS_SUCCESS; /* connect */ if ((status = __ntapi->ipc_connect_by_attr( &rtdata->hmsqctl, &msqctl->attr))) return status; /* update */ rtdata->msqctl_type = msqctl->attr.type; rtdata->msqctl_subtype = msqctl->attr.subtype; rtdata->msqctl_keys[0] = msqctl->attr.keys.key[0]; rtdata->msqctl_keys[1] = msqctl->attr.keys.key[1]; rtdata->msqctl_keys[2] = msqctl->attr.keys.key[2]; rtdata->msqctl_keys[3] = msqctl->attr.keys.key[3]; rtdata->msqctl_keys[4] = msqctl->attr.keys.key[4]; rtdata->msqctl_keys[5] = msqctl->attr.keys.key[5]; __ntapi->tt_guid_copy( &rtdata->msqctl_guid, &msqctl->attr.guid); return NT_STATUS_SUCCESS; } static int32_t __msqpid_symlink_set( nt_rtdata * rtdata, nt_tty_service_info * msqctl) { int32_t status; void * hpiddir; nt_port_name svcname; nt_unicode_string str; if (rtdata->hmsqpid) return NT_STATUS_SUCCESS; if (!rtdata->hmsqpiddir) { 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_msqpid,&g_msqpid))) return status; if (at_locked_cas((intptr_t *)&rtdata->hmsqpiddir,0,(intptr_t)hpiddir)) __ntapi->zw_close(hpiddir); } __ntapi->tt_port_name_from_attr( &svcname,&msqctl->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->hmsqpid, NT_SEC_STANDARD_RIGHTS_ALL, rtdata->hmsqpiddir, 0,&str, pe_get_current_process_id()); } static int32_t __stdcall __msq_open( void * hipc, nt_msq_info * msq, uint32_t access, nt_object_attributes * oa, nt_iosb * iosb, uint32_t share, uint32_t msqslots, uint32_t key, uint32_t id, uint32_t opcode) { int32_t status; nt_tty_port_msg msg; nt_iosb siosb; nt_tty_service_info msqctl; nt_runtime_data * rtdata; /* init */ rtdata = (__ntapi_internals())->rtdata; /* msqctl service attributes */ if (!rtdata->hmsqpid) if ((status = __msqctl_get_service_attr(rtdata,&msqctl))) return status; /* msqctl server */ if ((status = __msqctl_server_connect(rtdata,&msqctl))) return status; /* msqpid symlink */ if ((status = __msqpid_symlink_set(rtdata,&msqctl))) return status; /* hipc */ if (!hipc && (opcode == NT_TTY_MSQ_ALLOC)) hipc = (__ntapi_internals())->rtdata->hmsqctl; /* obtain msq 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_msq_info_msg) - sizeof(msg.header); msg.header.msg_size = sizeof(msg); msg.ttyinfo.opcode = opcode; msg.msqinfo.msqkey = (int32_t)key; msg.msqinfo.msqid = (int32_t)id; msg.msqinfo.msqslots = msqslots; msg.msqinfo.ntattr = oa->obj_attr; msg.msqinfo.ntaccess = access; msg.msqinfo.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 msqueue? */ if (opcode == NT_TTY_MSQ_ALLOC) if ((status = __ntapi->ipc_connect_by_attr( &hipc,&msg.svcinfo.attr))) return status; /* all done */ __ntapi->tt_aligned_block_memset( (uintptr_t *)msq, 0,sizeof(*msq)); msq->msqkey = msg.svcinfo.key; msq->msqid = msg.svcinfo.id; msq->hport = hipc; return NT_STATUS_SUCCESS; } int32_t __stdcall __ntapi_msq_create( __in void * hport, __out nt_msq_info * msq, __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 msqueue */ return __msq_open( hport,msq,access, oa,iosb,share,nslots, key,0,NT_TTY_MSQ_ALLOC); } int32_t __stdcall __ntapi_msq_open( __in void * hport, __out nt_msq_info * msq, __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 msqctl; /* 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 __msq_open( hport,msq,access, oa,iosb,share,nslots, key,0,NT_TTY_MSQ_ALLOC); else return status; default: return status; } /* msqctl service attributes */ if (!rtdata->hmsqpid) if ((status = __msqctl_get_service_attr(rtdata,&msqctl))) return status; /* msqctl server */ if ((status = __msqctl_server_connect(rtdata,&msqctl))) return status; /* msqpid symlink */ if ((status = __msqpid_symlink_set(rtdata,&msqctl))) 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 __msq_open( hipc,msq,access, oa,iosb,share,nslots, key,id,NT_TTY_MSQ_OPEN); }