1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Kernel Streaming 4 * FILE: drivers/wdm/audio/backpln/portcls/registry.cpp 5 * PURPOSE: Registry access object 6 * PROGRAMMER: Johannes Anderwald 7 */ 8 9 #include "private.hpp" 10 11 #ifndef YDEBUG 12 #define NDEBUG 13 #endif 14 15 #include <debug.h> 16 17 class CRegistryKey : public IRegistryKey 18 { 19 public: 20 STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface); 21 22 STDMETHODIMP_(ULONG) AddRef() 23 { 24 InterlockedIncrement(&m_Ref); 25 return m_Ref; 26 } 27 STDMETHODIMP_(ULONG) Release() 28 { 29 InterlockedDecrement(&m_Ref); 30 31 if (!m_Ref) 32 { 33 delete this; 34 return 0; 35 } 36 return m_Ref; 37 } 38 39 IMP_IRegistryKey; 40 CRegistryKey(IUnknown * OuterUnknown, HANDLE hKey, BOOL CanDelete) : m_hKey(hKey), m_Deleted(FALSE), m_CanDelete(CanDelete), m_Ref(0){} 41 virtual ~CRegistryKey(); 42 43 protected: 44 45 HANDLE m_hKey; 46 BOOL m_Deleted; 47 BOOL m_CanDelete; 48 LONG m_Ref; 49 }; 50 51 CRegistryKey::~CRegistryKey() 52 { 53 if (!m_Deleted) 54 { 55 // close key only when has not been deleted yet 56 ZwClose(m_hKey); 57 } 58 } 59 60 61 NTSTATUS 62 NTAPI 63 CRegistryKey::QueryInterface( 64 IN REFIID refiid, 65 OUT PVOID* Output) 66 { 67 UNICODE_STRING GuidString; 68 69 DPRINT("CRegistryKey::QueryInterface entered\n"); 70 if (IsEqualGUIDAligned(refiid, IID_IRegistryKey) || 71 IsEqualGUIDAligned(refiid, IID_IUnknown)) 72 { 73 *Output = PVOID(PREGISTRYKEY(this)); 74 PUNKNOWN(*Output)->AddRef(); 75 return STATUS_SUCCESS; 76 } 77 78 if (RtlStringFromGUID(refiid, &GuidString) == STATUS_SUCCESS) 79 { 80 DPRINT1("CRegistryKey::QueryInterface no interface!!! iface %S\n", GuidString.Buffer); 81 RtlFreeUnicodeString(&GuidString); 82 } 83 84 return STATUS_UNSUCCESSFUL; 85 } 86 87 NTSTATUS 88 NTAPI 89 CRegistryKey::DeleteKey() 90 { 91 NTSTATUS Status; 92 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); 93 94 if (m_Deleted) 95 { 96 // key already deleted 97 return STATUS_INVALID_HANDLE; 98 } 99 100 if (!m_CanDelete) 101 { 102 // only general keys can be deleted 103 return STATUS_ACCESS_DENIED; 104 } 105 106 // delete key 107 Status = ZwDeleteKey(m_hKey); 108 if (NT_SUCCESS(Status)) 109 { 110 m_Deleted = TRUE; 111 m_hKey = NULL; 112 } 113 return Status; 114 } 115 116 NTSTATUS 117 NTAPI 118 CRegistryKey::EnumerateKey( 119 IN ULONG Index, 120 IN KEY_INFORMATION_CLASS KeyInformationClass, 121 OUT PVOID KeyInformation, 122 IN ULONG Length, 123 OUT PULONG ResultLength) 124 { 125 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); 126 127 if (m_Deleted) 128 { 129 return STATUS_INVALID_HANDLE; 130 } 131 132 return ZwEnumerateKey(m_hKey, Index, KeyInformationClass, KeyInformation, Length, ResultLength); 133 } 134 135 NTSTATUS 136 NTAPI 137 CRegistryKey::EnumerateValueKey( 138 IN ULONG Index, 139 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, 140 OUT PVOID KeyValueInformation, 141 IN ULONG Length, 142 OUT PULONG ResultLength) 143 { 144 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); 145 146 if (m_Deleted) 147 { 148 return STATUS_INVALID_HANDLE; 149 } 150 151 return ZwEnumerateValueKey(m_hKey, Index, KeyValueInformationClass, KeyValueInformation, Length, ResultLength); 152 } 153 154 NTSTATUS 155 NTAPI 156 CRegistryKey::NewSubKey( 157 OUT PREGISTRYKEY *RegistrySubKey, 158 IN PUNKNOWN OuterUnknown, 159 IN ACCESS_MASK DesiredAccess, 160 IN PUNICODE_STRING SubKeyName, 161 IN ULONG CreateOptions, 162 OUT PULONG Disposition OPTIONAL) 163 { 164 OBJECT_ATTRIBUTES Attributes; 165 NTSTATUS Status; 166 HANDLE hKey; 167 CRegistryKey * RegistryKey; 168 169 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); 170 171 DPRINT("CRegistryKey::NewSubKey entered %S\n", SubKeyName->Buffer); 172 173 if (m_Deleted) 174 { 175 return STATUS_INVALID_HANDLE; 176 } 177 178 InitializeObjectAttributes(&Attributes, SubKeyName, OBJ_INHERIT | OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_KERNEL_HANDLE, m_hKey, NULL); 179 Status = ZwCreateKey(&hKey, DesiredAccess, &Attributes, 0, NULL, CreateOptions, Disposition); 180 if (!NT_SUCCESS(Status)) 181 { 182 DPRINT("CRegistryKey::NewSubKey failed with %x\n", Status); 183 return Status; 184 } 185 186 RegistryKey = new(NonPagedPool, TAG_PORTCLASS)CRegistryKey(OuterUnknown, hKey, TRUE); 187 if (!RegistryKey) 188 return STATUS_INSUFFICIENT_RESOURCES; 189 190 Status = RegistryKey->QueryInterface(IID_IRegistryKey, (PVOID*)RegistrySubKey); 191 192 if (!NT_SUCCESS(Status)) 193 { 194 delete RegistryKey; 195 return Status; 196 } 197 198 DPRINT("CRegistryKey::NewSubKey RESULT %p\n", *RegistrySubKey); 199 return STATUS_SUCCESS; 200 } 201 202 NTSTATUS 203 NTAPI 204 CRegistryKey::QueryKey( 205 IN KEY_INFORMATION_CLASS KeyInformationClass, 206 OUT PVOID KeyInformation, 207 IN ULONG Length, 208 OUT PULONG ResultLength) 209 { 210 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); 211 212 if (m_Deleted) 213 { 214 return STATUS_INVALID_HANDLE; 215 } 216 217 return ZwQueryKey(m_hKey, KeyInformationClass, KeyInformation, Length, ResultLength); 218 } 219 220 NTSTATUS 221 NTAPI 222 CRegistryKey::QueryRegistryValues( 223 IN PRTL_QUERY_REGISTRY_TABLE QueryTable, 224 IN PVOID Context OPTIONAL) 225 { 226 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); 227 228 if (m_Deleted) 229 { 230 return STATUS_INVALID_HANDLE; 231 } 232 233 return RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, (PCWSTR)m_hKey, QueryTable, Context, NULL); 234 } 235 236 NTSTATUS 237 NTAPI 238 CRegistryKey::QueryValueKey( 239 IN PUNICODE_STRING ValueName, 240 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, 241 OUT PVOID KeyValueInformation, 242 IN ULONG Length, 243 OUT PULONG ResultLength) 244 { 245 NTSTATUS Status; 246 247 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); 248 249 if (m_Deleted) 250 { 251 return STATUS_INVALID_HANDLE; 252 } 253 254 Status = ZwQueryValueKey(m_hKey, ValueName, KeyValueInformationClass, KeyValueInformation, Length, ResultLength); 255 DPRINT("CRegistryKey::QueryValueKey entered %p value %wZ Status %x\n", this, ValueName, Status); 256 return Status; 257 } 258 259 NTSTATUS 260 NTAPI 261 CRegistryKey::SetValueKey( 262 IN PUNICODE_STRING ValueName OPTIONAL, 263 IN ULONG Type, 264 IN PVOID Data, 265 IN ULONG DataSize 266 ) 267 { 268 DPRINT("CRegistryKey::SetValueKey entered %S\n", ValueName->Buffer); 269 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); 270 271 if (m_Deleted) 272 { 273 return STATUS_INVALID_HANDLE; 274 } 275 276 return ZwSetValueKey(m_hKey, ValueName, 0, Type, Data, DataSize); 277 } 278 279 NTSTATUS 280 NTAPI 281 PcNewRegistryKey( 282 OUT PREGISTRYKEY* OutRegistryKey, 283 IN PUNKNOWN OuterUnknown OPTIONAL, 284 IN ULONG RegistryKeyType, 285 IN ACCESS_MASK DesiredAccess, 286 IN PVOID DeviceObject OPTIONAL, 287 IN PVOID SubDevice OPTIONAL, 288 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 289 IN ULONG CreateOptions OPTIONAL, 290 OUT PULONG Disposition OPTIONAL) 291 { 292 HANDLE hHandle; 293 NTSTATUS Status = STATUS_UNSUCCESSFUL; 294 CRegistryKey * RegistryKey; 295 PPCLASS_DEVICE_EXTENSION DeviceExt; 296 PSUBDEVICE_DESCRIPTOR SubDeviceDescriptor; 297 ISubdevice * Device; 298 PSYMBOLICLINK_ENTRY SymEntry; 299 BOOL CanDelete = FALSE; 300 301 DPRINT("PcNewRegistryKey entered\n"); 302 303 if (!OutRegistryKey) 304 return STATUS_INVALID_PARAMETER; 305 306 if (RegistryKeyType != GeneralRegistryKey && 307 RegistryKeyType != DeviceRegistryKey && 308 RegistryKeyType != DriverRegistryKey && 309 RegistryKeyType != HwProfileRegistryKey && 310 RegistryKeyType != DeviceInterfaceRegistryKey) 311 { 312 return STATUS_INVALID_PARAMETER; 313 } 314 315 // check for the key type 316 if (RegistryKeyType == GeneralRegistryKey) 317 { 318 // do we have the required object attributes 319 if (!ObjectAttributes) 320 { 321 // object attributes is mandatory 322 return STATUS_INVALID_PARAMETER; 323 } 324 // try to create the key 325 Status = ZwCreateKey(&hHandle, DesiredAccess, ObjectAttributes, 0, NULL, CreateOptions, Disposition); 326 327 // key can be deleted 328 CanDelete = TRUE; 329 } 330 else if (RegistryKeyType == DeviceRegistryKey || 331 RegistryKeyType == DriverRegistryKey || 332 RegistryKeyType == HwProfileRegistryKey) 333 { 334 // check for HwProfileRegistryKey case 335 if (RegistryKeyType == HwProfileRegistryKey) 336 { 337 // IoOpenDeviceRegistryKey used different constant 338 RegistryKeyType = PLUGPLAY_REGKEY_CURRENT_HWPROFILE | PLUGPLAY_REGKEY_DEVICE; 339 } 340 341 // obtain the new device extension 342 DeviceExt = (PPCLASS_DEVICE_EXTENSION) ((PDEVICE_OBJECT)DeviceObject)->DeviceExtension; 343 344 Status = IoOpenDeviceRegistryKey(DeviceExt->PhysicalDeviceObject, RegistryKeyType, DesiredAccess, &hHandle); 345 } 346 else if (RegistryKeyType == DeviceInterfaceRegistryKey) 347 { 348 if (SubDevice == NULL) 349 { 350 // invalid parameter 351 return STATUS_INVALID_PARAMETER; 352 } 353 354 // look up our undocumented interface 355 Status = ((PUNKNOWN)SubDevice)->QueryInterface(IID_ISubdevice, (LPVOID*)&Device); 356 357 if (!NT_SUCCESS(Status)) 358 { 359 DPRINT("No ISubdevice interface\n"); 360 // invalid parameter 361 return STATUS_INVALID_PARAMETER; 362 } 363 364 // get the subdevice descriptor 365 Status = Device->GetDescriptor(&SubDeviceDescriptor); 366 if (!NT_SUCCESS(Status)) 367 { 368 DPRINT("Failed to get subdevice descriptor %x\n", Status); 369 ((PUNKNOWN)SubDevice)->Release(); 370 return STATUS_UNSUCCESSFUL; 371 } 372 373 // is there an registered device interface 374 if (IsListEmpty(&SubDeviceDescriptor->SymbolicLinkList)) 375 { 376 DPRINT("No device interface registered\n"); 377 ((PUNKNOWN)SubDevice)->Release(); 378 return STATUS_UNSUCCESSFUL; 379 } 380 381 // get the first symbolic link 382 SymEntry = (PSYMBOLICLINK_ENTRY)CONTAINING_RECORD(SubDeviceDescriptor->SymbolicLinkList.Flink, SYMBOLICLINK_ENTRY, Entry); 383 384 // open device interface 385 Status = IoOpenDeviceInterfaceRegistryKey(&SymEntry->SymbolicLink, DesiredAccess, &hHandle); 386 387 // release subdevice interface 388 ((PUNKNOWN)SubDevice)->Release(); 389 } 390 391 // check for success 392 if (!NT_SUCCESS(Status)) 393 { 394 DPRINT1("PcNewRegistryKey failed with %lx\n", Status); 395 return Status; 396 } 397 398 // allocate new registry key object 399 RegistryKey = new(NonPagedPool, TAG_PORTCLASS)CRegistryKey(OuterUnknown, hHandle, CanDelete); 400 if (!RegistryKey) 401 { 402 // not enough memory 403 ZwClose(hHandle); 404 return STATUS_INSUFFICIENT_RESOURCES; 405 } 406 407 // query for interface 408 Status = RegistryKey->QueryInterface(IID_IRegistryKey, (PVOID*)OutRegistryKey); 409 410 if (!NT_SUCCESS(Status)) 411 { 412 // out of memory 413 delete RegistryKey; 414 } 415 416 DPRINT("PcNewRegistryKey result %p\n", *OutRegistryKey); 417 return STATUS_SUCCESS; 418 } 419