From: Aric Stewart Subject: [PATCH 1/2] ntoskrnl.exe: Implement IoRegisterDeviceInterface Message-Id: <857d40f3-1cce-ed28-1a10-819e98daf5fa@codeweavers.com> Date: Fri, 14 Sep 2018 13:59:18 -0500 Signed-off-by: Aric Stewart --- dlls/ntoskrnl.exe/ntoskrnl.c | 216 ++++++++++++++++++++++++++++++++++++ dlls/ntoskrnl.exe/ntoskrnl.exe.spec | 2 +- include/ddk/wdm.h | 1 + 3 files changed, 218 insertions(+), 1 deletion(-) diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c index 18524afb07..759649061e 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/ntoskrnl.c @@ -1665,6 +1665,222 @@ NTSTATUS WINAPI IoQueryDeviceDescription(PINTERFACE_TYPE itype, PULONG bus, PCON } +static NTSTATUS create_reg_tree(const WCHAR *key, HANDLE *key_out) +{ + HANDLE hkey; + WCHAR *ptr; + OBJECT_ATTRIBUTES attr; + UNICODE_STRING keypath; + BOOL done = FALSE; + NTSTATUS status; + WCHAR *buff; + + buff = HeapAlloc( GetProcessHeap(), 0, (strlenW(key)+1) * sizeof(WCHAR) ); + strcpyW( buff, key ); + + ptr = buff + 18; + ptr = strchrW( ptr, '\\' ); + while (!done) + { + if (ptr) + *ptr = 0; + + RtlInitUnicodeString( &keypath, buff ); + InitializeObjectAttributes( &attr, &keypath, 0, NULL, NULL ); + + status = NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ); + if ( status != STATUS_SUCCESS ) + { + ERR( "Registry key failed on: %s\n", debugstr_w(buff) ); + HeapFree( GetProcessHeap(), 0, buff ); + return status; + } + if (ptr) + { + *ptr = '\\'; + ptr++; + ptr = strchrW( ptr, '\\' ); + NtClose( hkey ); + } + else + done = TRUE; + } + + *key_out = hkey; + HeapFree( GetProcessHeap(), 0, buff ); + return STATUS_SUCCESS; +} + + +static void guid_to_string(const GUID *guid, WCHAR *guidStr) +{ + static const WCHAR fmt[] = {'{','%','0','8','X','-','%','0','4','X','-', + '%','0','4','X','-','%','0','2','X','%','0','2','X','-','%','0','2', + 'X','%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X','%', + '0','2','X','}',0}; + + sprintfW( guidStr, fmt, guid->Data1, guid->Data2, guid->Data3, + guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], + guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7] ); +} + + +static NTSTATUS get_instance_id(DEVICE_OBJECT *device, WCHAR **instance_id) +{ + WCHAR *id, *ptr; + NTSTATUS status; + + status = get_device_id( device, BusQueryInstanceID, &id ); + if (status != STATUS_SUCCESS) + { + FIXME( "failed to get device ID\n" ); + return status; + } + + struprW( id ); + ptr = strchrW( id, '\\' ); + + while (ptr) + { + *ptr = '#'; + ptr = strchrW( id,'\\' ); + } + + *instance_id = id; + return STATUS_SUCCESS; +} + + +static NTSTATUS create_interface_registry_path(const WCHAR *instance_id, const GUID *class_guid, WCHAR **keypath) +{ + static const WCHAR fmtW[] = {'\\','R','e','g','i','s','t','r','y', + '\\','M','a','c','h','i','n','e', + '\\','S','y','s','t','e','m', + '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t', + '\\','C','o','n','t','r','o','l', + '\\','D','e','v','i','c','e','C','l','a','s','s','e','s', + '\\','%','s', + '\\','#','#','?','#','%','s','#','%','s',0}; + WCHAR *buff; + WCHAR guidStr[39]; + + guid_to_string( class_guid, guidStr ); + + buff = HeapAlloc( GetProcessHeap(), 0, sizeof(fmtW) + sizeof(guidStr) * 2 + strlenW(instance_id) * sizeof(WCHAR) ); + sprintfW( buff, fmtW, guidStr, instance_id, guidStr ); + + *keypath = buff; + + return STATUS_SUCCESS; +} + + +static WCHAR* create_symbolic_link_path(const WCHAR *instance_id, const GUID *class_guid, const WCHAR *reference_string) +{ + static const WCHAR fmt[] = {'\\','\\','?','\\','%','s','#','%','s',0}; + WCHAR guidStr[39]; + DWORD len; + WCHAR *ret; + + guid_to_string( class_guid, guidStr ); + /* omit length of format specifiers, but include NULL terminator: */ + len = strlenW( fmt ) - 4 + 1; + len += strlenW( instance_id ) + strlenW( guidStr ); + if ( reference_string && *reference_string ) + { + /* space for a hash between string and reference string: */ + len += strlenW( reference_string ) + 1; + } + ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); + if (ret) + { + WCHAR *ptr; + int printed = sprintfW( ret, fmt, instance_id, guidStr ); + + /* replace '\\' with '#' after the "\\\\?\\" beginning */ + for (ptr = strchrW( ret + 4, '\\' ); ptr; ptr = strchrW( ptr + 1, '\\') ) + *ptr = '#'; + if (reference_string && *reference_string) + { + ret[printed] = '\\'; + strcpyW( ret + printed + 1, reference_string ); + } + } + return ret; +} + + +/***************************************************** + * IoRegisterDeviceInterface(NTOSKRNL.EXE.@) + */ +NTSTATUS WINAPI IoRegisterDeviceInterface(DEVICE_OBJECT *device, const GUID *class_guid, UNICODE_STRING *reference_string, UNICODE_STRING *symbolic_link) +{ + static const WCHAR device_instanceW[] = {'D','e','v','i','c','e','I','n','s','t','a','n','c','e',0}; + static const WCHAR hashW[] = {'#',0}; + WCHAR *id; + WCHAR *regKey, *instance_id; + HANDLE hkey, subkey; + NTSTATUS status = STATUS_SUCCESS; + UNICODE_STRING regStr; + OBJECT_ATTRIBUTES attr; + + TRACE( "(%p, %s, %s, %p)\n", device, debugstr_guid(class_guid), debugstr_us(reference_string), symbolic_link ); + + get_device_id( device, BusQueryInstanceID, &id ); + + status = get_instance_id( device, &instance_id ); + if (status != STATUS_SUCCESS) + { + ERR( "Failed to generate Instance ID\n" ); + return status; + } + create_interface_registry_path( instance_id, class_guid, ®Key ); + status = create_reg_tree( regKey, &hkey ); + if (status != STATUS_SUCCESS) + { + ERR( "Failed to create registry tree\n" ); + HeapFree( GetProcessHeap(), 0, id ); + HeapFree( GetProcessHeap(), 0, instance_id ); + HeapFree( GetProcessHeap(), 0, regKey ); + return status; + } + + RtlInitUnicodeString( ®Str, device_instanceW ); + NtSetValueKey( hkey, ®Str, 0, REG_SZ, id, (strlenW(id)+1)*sizeof(WCHAR) ); + RtlInitUnicodeString( ®Str, hashW ); + InitializeObjectAttributes( &attr, ®Str, 0, hkey, NULL ); + + status = NtCreateKey( &subkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ); + if (status != STATUS_SUCCESS) + { + ERR( "subkey creation failed\n" ); + } + else + { + static const WCHAR symbolic_linkW[] = {'S','y','m','b','o','l','i','c','L','i','n','k',0}; + WCHAR *linkName; + + linkName = create_symbolic_link_path( instance_id, class_guid, reference_string?reference_string->Buffer:NULL ); + RtlInitUnicodeString( ®Str, symbolic_linkW ); + NtSetValueKey( subkey, ®Str, 0, REG_SZ, linkName, (strlenW(linkName)+1)*sizeof(WCHAR) ); + if (symbolic_link) + { + linkName[1] = '?'; + RtlCreateUnicodeString( symbolic_link, linkName ); + } + HeapFree( GetProcessHeap(), 0, linkName ); + NtClose( subkey ); + } + + NtClose( hkey ); + HeapFree( GetProcessHeap(), 0, id ); + HeapFree( GetProcessHeap(), 0, instance_id ); + HeapFree( GetProcessHeap(), 0, regKey ); + + return status; +} + + /*********************************************************************** * IoRegisterDriverReinitialization (NTOSKRNL.EXE.@) */ diff --git a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec index 12f9ddb096..449ba763a1 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec +++ b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec @@ -428,7 +428,7 @@ @ stub IoReadPartitionTableEx @ stub IoReadTransferCount @ stub IoRegisterBootDriverReinitialization -@ stub IoRegisterDeviceInterface +@ stdcall IoRegisterDeviceInterface(ptr ptr ptr ptr) @ stdcall IoRegisterDriverReinitialization(ptr ptr ptr) @ stdcall IoRegisterFileSystem(ptr) @ stub IoRegisterFsRegistrationChange diff --git a/include/ddk/wdm.h b/include/ddk/wdm.h index 0cd1673dbe..cd057d5a9f 100644 --- a/include/ddk/wdm.h +++ b/include/ddk/wdm.h @@ -1405,6 +1405,7 @@ PDEVICE_OBJECT WINAPI IoGetRelatedDeviceObject(PFILE_OBJECT); void WINAPI IoInitializeIrp(IRP*,USHORT,CCHAR); VOID WINAPI IoInitializeRemoveLockEx(PIO_REMOVE_LOCK,ULONG,ULONG,ULONG,ULONG); void WINAPI IoInvalidateDeviceRelations(PDEVICE_OBJECT,DEVICE_RELATION_TYPE); +NTSTATUS WINAPI IoRegisterDeviceInterface(PDEVICE_OBJECT,const GUID*,PUNICODE_STRING,PUNICODE_STRING); void WINAPI IoReleaseCancelSpinLock(KIRQL); NTSTATUS WINAPI IoSetDeviceInterfaceState(UNICODE_STRING*,BOOLEAN); NTSTATUS WINAPI IoWMIRegistrationControl(PDEVICE_OBJECT,ULONG);