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