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