NTSTATUS NTAPI NtQueryValueKey( HANDLE KeyHandle, PUNICODE_STRING ValueName, KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, PVOID KeyValueInformation, ULONG KeyValueInformationLength, PULONG ResultLength ) { unicode_string_t us; NTSTATUS r; ULONG len; regkey_t *key; regval_t *val; trace("%p %p %d %p %lu %p\n", KeyHandle, ValueName, KeyValueInformationClass, KeyValueInformation, KeyValueInformationLength, ResultLength ); r = check_key_value_info_class( KeyValueInformationClass ); if (r < STATUS_SUCCESS) return r; r = object_from_handle( key, KeyHandle, KEY_QUERY_VALUE ); if (r < STATUS_SUCCESS) return r; r = us.copy_from_user( ValueName ); if (r < STATUS_SUCCESS) return r; r = verify_for_write( ResultLength, sizeof *ResultLength ); if (r < STATUS_SUCCESS) return r; trace("%pus\n", &us ); val = key_find_value( key, &us ); if (!val) return STATUS_OBJECT_NAME_NOT_FOUND; r = reg_query_value( val, KeyValueInformationClass, KeyValueInformation, KeyValueInformationLength, len ); copy_to_user( ResultLength, &len, sizeof len ); return r; }
NTSTATUS NTAPI NtSetContextThread( HANDLE ThreadHandle, PCONTEXT Context) { dprintf("%p %p\n", ThreadHandle, Context ); thread_impl_t *t = 0; NTSTATUS r = object_from_handle( t, ThreadHandle, 0 ); if (r < STATUS_SUCCESS) return r; CONTEXT c; r = copy_from_user( &c, Context, sizeof c ); if (r < STATUS_SUCCESS) return r; t->set_context( c ); return STATUS_SUCCESS; }
NTSTATUS NTAPI NtQueryEvent( HANDLE Handle, EVENT_INFORMATION_CLASS EventInformationClass, PVOID EventInformation, ULONG EventInformationLength, PULONG ReturnLength) { event_t *event; NTSTATUS r; r = object_from_handle( event, Handle, EVENT_QUERY_STATE ); if (r < STATUS_SUCCESS) return r; union { EVENT_BASIC_INFORMATION basic; } info; ULONG sz = 0; switch (EventInformationClass) { case EventBasicInformation: sz = sizeof info.basic; break; default: return STATUS_INVALID_INFO_CLASS; } if (sz != EventInformationLength) return STATUS_INFO_LENGTH_MISMATCH; event->query( info.basic ); r = copy_to_user( EventInformation, &info, sz ); if (r < STATUS_SUCCESS) return r; if (ReturnLength) copy_to_user( ReturnLength, &sz, sizeof sz ); return r; }
NTSTATUS NTAPI NtSetValueKey( HANDLE KeyHandle, PUNICODE_STRING ValueName, ULONG TitleIndex, ULONG Type, PVOID Data, ULONG DataSize ) { unicode_string_t us; regkey_t *key; NTSTATUS r; trace("%p %p %lu %lu %p %lu\n", KeyHandle, ValueName, TitleIndex, Type, Data, DataSize ); r = object_from_handle( key, KeyHandle, KEY_SET_VALUE ); if (r < STATUS_SUCCESS) return r; r = us.copy_from_user( ValueName ); if (r == STATUS_SUCCESS) { regval_t *val; val = new regval_t( &us, Type, DataSize ); if (val) { r = copy_from_user( val->data, Data, DataSize ); if (r == STATUS_SUCCESS) { delete_value( key, &us ); key->values.append( val ); } else delete val; } else r = STATUS_NO_MEMORY; } return r; }
NTSTATUS NTAPI NtTerminateThread( HANDLE ThreadHandle, NTSTATUS Status) { thread_t *t; NTSTATUS r; dprintf("%p %08lx\n", ThreadHandle, Status); if (ThreadHandle == 0) t = current; else { r = object_from_handle( t, ThreadHandle, 0 ); if (r < STATUS_SUCCESS) return r; } // If we killed ourselves we'll return the the scheduler but never run again. return t->terminate( Status ); }
NTSTATUS NTAPI NtResumeThread( HANDLE ThreadHandle, PULONG PreviousSuspendCount ) { thread_t *thread; ULONG count = 0; NTSTATUS r; dprintf("%p %p\n", ThreadHandle, PreviousSuspendCount ); r = object_from_handle( thread, ThreadHandle, 0 ); if (r < STATUS_SUCCESS) return r; r = thread->resume( &count ); if (r == STATUS_SUCCESS && PreviousSuspendCount) r = copy_to_user( PreviousSuspendCount, &count, sizeof count ); return r; }
NTSTATUS NTAPI NtNotifyChangeKey( HANDLE KeyHandle, HANDLE EventHandle, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, ULONG NotifyFilter, BOOLEAN WatchSubtree, PVOID Buffer, ULONG BufferLength, BOOLEAN Asynchronous) { regkey_t *key = 0; NTSTATUS r = object_from_handle( key, KeyHandle, 0 ); if (r < STATUS_SUCCESS) return r; trace("does nothing...\n"); return STATUS_SUCCESS; }
NTSTATUS NTAPI NtDeleteValueKey( HANDLE KeyHandle, PUNICODE_STRING ValueName ) { unicode_string_t us; NTSTATUS r; regkey_t *key; trace("%p %p\n", KeyHandle, ValueName); r = us.copy_from_user( ValueName ); if (r < STATUS_SUCCESS) return r; r = object_from_handle( key, KeyHandle, KEY_SET_VALUE ); if (r < STATUS_SUCCESS) return r; r = delete_value( key, &us ); return r; }
NTSTATUS NTAPI NtQueryKey( HANDLE KeyHandle, KEY_INFORMATION_CLASS KeyInformationClass, PVOID KeyInformation, ULONG KeyInformationLength, PULONG ReturnLength) { if (!key_info_class_valid(KeyInformationClass)) return STATUS_INVALID_INFO_CLASS; NTSTATUS r; r = verify_for_write( ReturnLength, sizeof *ReturnLength ); if (r < STATUS_SUCCESS) return r; regkey_t *key = 0; r = object_from_handle( key, KeyHandle, KEY_QUERY_VALUE ); if (r < STATUS_SUCCESS) return r; return key->query( KeyInformationClass, KeyInformation, KeyInformationLength, ReturnLength ); }
NTSTATUS open_key( regkey_t **out, OBJECT_ATTRIBUTES *oa ) { UNICODE_STRING parsed_name; regkey_t *key = root_key; NTSTATUS r; if (oa->RootDirectory) { r = object_from_handle( key, oa->RootDirectory, 0 ); if (r < STATUS_SUCCESS) return r; } else key = root_key; memcpy( &parsed_name, oa->ObjectName, sizeof parsed_name ); r = open_parse_key( key, &parsed_name, oa->Attributes & OBJ_CASE_INSENSITIVE ); if (r == STATUS_SUCCESS) *out = key; return r; }
NTSTATUS NTAPI NtEnumerateValueKey( HANDLE KeyHandle, ULONG Index, KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, PVOID KeyValueInformation, ULONG KeyValueInformationLength, PULONG ResultLength ) { regkey_t *key; ULONG len = 0; NTSTATUS r = STATUS_SUCCESS; trace("%p %lu %u %p %lu %p\n", KeyHandle, Index, KeyValueInformationClass, KeyValueInformation, KeyValueInformationLength, ResultLength ); r = object_from_handle( key, KeyHandle, KEY_QUERY_VALUE ); if (r < STATUS_SUCCESS) return r; r = verify_for_write( ResultLength, sizeof *ResultLength ); if (r < STATUS_SUCCESS) return r; regval_iter i(key->values); for ( ; i && Index; i.next()) Index--; if (!i) return STATUS_NO_MORE_ENTRIES; r = reg_query_value( i, KeyValueInformationClass, KeyValueInformation, KeyValueInformationLength, len ); copy_to_user( ResultLength, &len, sizeof len ); return r; }
NTSTATUS open_root( object_t*& obj, open_info_t& info ) { // look each directory in the path and make sure it exists object_dir_t *dir = 0; NTSTATUS r; // parse the root directory if (info.root) { // relative path if (info.path.Buffer[0] == '\\') return STATUS_OBJECT_PATH_SYNTAX_BAD; r = object_from_handle( dir, info.root, DIRECTORY_QUERY ); if (r < STATUS_SUCCESS) return r; } else { // absolute path if (info.path.Buffer[0] != '\\') return STATUS_OBJECT_PATH_SYNTAX_BAD; dir = root; info.path.Buffer++; info.path.Length -= 2; } if (info.path.Length == 0) { obj = dir; return info.on_open( 0, obj, info ); } return dir->open( obj, info ); }
NTSTATUS nteventfunc( HANDLE Handle, PULONG PreviousState, void (event_t::*fn)(PULONG) ) { NTSTATUS r; ULONG prev; if (PreviousState) { r = verify_for_write( PreviousState, sizeof PreviousState ); if (r < STATUS_SUCCESS) return r; } event_t *event = 0; r = object_from_handle( event, Handle, EVENT_MODIFY_STATE ); if (r < STATUS_SUCCESS) return r; (event->*fn)( &prev ); if (PreviousState) copy_to_user( PreviousState, &prev, sizeof prev ); return r; }
NTSTATUS NTAPI NtQueryInformationThread( HANDLE ThreadHandle, THREADINFOCLASS ThreadInformationClass, PVOID ThreadInformation, ULONG ThreadInformationLength, PULONG ReturnLength) { union { THREAD_BASIC_INFORMATION basic; KERNEL_USER_TIMES times; ULONG last_thread; } info; ULONG sz = 0; NTSTATUS r; thread_impl_t *t; dprintf("%p %d %p %lu %p\n", ThreadHandle, ThreadInformationClass, ThreadInformation, ThreadInformationLength, ReturnLength); switch( ThreadInformationClass ) { case ThreadBasicInformation: sz = sizeof info.basic; break; case ThreadTimes: sz = sizeof info.times; break; case ThreadAmILastThread: sz = sizeof info.last_thread; break; default: dprintf("info class %d\n", ThreadInformationClass); return STATUS_INVALID_INFO_CLASS; } if (sz != ThreadInformationLength) return STATUS_INFO_LENGTH_MISMATCH; memset( &info, 0, sizeof info ); r = object_from_handle( t, ThreadHandle, 0 ); if (r < STATUS_SUCCESS) return r; if (ReturnLength) { r = verify_for_write( ReturnLength, sizeof *ReturnLength ); if (r < STATUS_SUCCESS) return r; } switch( ThreadInformationClass ) { case ThreadBasicInformation: t->query_information( info.basic ); break; case ThreadTimes: t->query_information( info.times ); break; case ThreadAmILastThread: info.last_thread = t->is_last_thread(); break; default: assert(0); } r = copy_to_user( ThreadInformation, &info, sz ); if (r == STATUS_SUCCESS && ReturnLength) copy_to_user( ReturnLength, &sz, sizeof sz ); return r; }
NTSTATUS thread_impl_t::wait_on_handles( ULONG count, PHANDLE handles, WAIT_TYPE type, BOOLEAN alert, PLARGE_INTEGER timeout) { NTSTATUS r = STATUS_SUCCESS; Alertable = alert; WaitType = type; // iterate the array and wait on each handle for (ULONG i=0; i<count; i++) { dprintf("handle[%ld] = %08lx\n", i, (ULONG) handles[i]); object_t *any = 0; r = object_from_handle( any, handles[i], SYNCHRONIZE ); if (r < STATUS_SUCCESS) { end_wait(); return r; } sync_object_t *obj = dynamic_cast<sync_object_t*>( any ); if (!obj) { end_wait(); return STATUS_INVALID_HANDLE; } r = wait_on( obj ); if (r < STATUS_SUCCESS) { end_wait(); return r; } } // make sure we wait for a little bit every time LARGE_INTEGER t; if (timeout && timeout->QuadPart <= 0 && timeout->QuadPart> -100000LL) { t.QuadPart = -100000LL; timeout = &t; } set_timeout( timeout ); while (1) { r = check_wait(); if (r != STATUS_PENDING) break; if (alerted) { alerted = FALSE; r = STATUS_ALERTED; break; } if (timeout && has_expired()) { r = STATUS_TIMEOUT; break; } in_wait = TRUE; wait(); assert( in_wait == FALSE ); } end_wait(); set_timeout( 0 ); return r; }
NTSTATUS NTAPI NtCreateSection( PHANDLE SectionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PLARGE_INTEGER SectionSize, ULONG Protect, ULONG Attributes, HANDLE FileHandle ) { NTSTATUS r; object_t *file = NULL; LARGE_INTEGER sz; trace("%p %08lx %p %p %08lx %08lx %p\n", SectionHandle, DesiredAccess, ObjectAttributes, SectionSize, Protect, Attributes, FileHandle ); // check there's no bad flags if (Attributes & ~VALID_SECTION_FLAGS) return STATUS_INVALID_PARAMETER_6; switch (Attributes & (SEC_IMAGE|SEC_COMMIT|SEC_RESERVE)) { case SEC_IMAGE: case SEC_RESERVE: case SEC_COMMIT: break; default: return STATUS_INVALID_PARAMETER_6; } r = verify_for_write( SectionHandle, sizeof *SectionHandle ); if (r < STATUS_SUCCESS) return r; // PE sections cannot be written to if (Attributes & SEC_IMAGE) { switch (Protect) { case PAGE_READONLY: case PAGE_EXECUTE: case PAGE_EXECUTE_READ: break; default: return STATUS_INVALID_PAGE_PROTECTION; } if (!FileHandle) return STATUS_INVALID_FILE_FOR_SECTION; r = object_from_handle( file, FileHandle, 0 ); if (r < STATUS_SUCCESS) return r; SectionSize = 0; } else { switch (Protect) { case PAGE_READONLY: case PAGE_READWRITE: case PAGE_EXECUTE: case PAGE_EXECUTE_READ: case PAGE_WRITECOPY: case PAGE_EXECUTE_READWRITE: case PAGE_EXECUTE_WRITECOPY: break; default: return STATUS_INVALID_PAGE_PROTECTION; } if (FileHandle) { r = object_from_handle( file, FileHandle, 0 ); if (r < STATUS_SUCCESS) return r; } } if (SectionSize) { r = copy_from_user( &sz, SectionSize, sizeof sz ); if (r < STATUS_SUCCESS) return r; if (sz.QuadPart == 0) return STATUS_INVALID_PARAMETER_4; SectionSize = &sz; } section_factory factory( file, SectionSize, Attributes, Protect ); return factory.create( SectionHandle, DesiredAccess, ObjectAttributes ); }