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