- Get autochk, calc, cmd, devmgr, expand, format, gettype, hostname, lsass, msconfig...
[reactos.git] / reactos / subsys / system / regedit / security.c
1 /*
2 * Regedit ACL Editor for Registry Keys
3 *
4 * Copyright (C) 2004 Thomas Weidenmueller <w3seek@reactos.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include <regedit.h>
22
23 #define INITGUID
24 #include <guiddef.h>
25
26 DEFINE_GUID(IID_CRegKeySecurity, 0x965fc360, 0x16ff, 0x11d0, 0x0091, 0xcb,0x00,0xaa,0x00,0xbb,0xb7,0x23);
27
28 /******************************************************************************
29 Implementation of the CRegKeySecurity interface
30 ******************************************************************************/
31
32 static ifaceCRegKeySecurityVbtl efvt =
33 {
34 /* IUnknown methods */
35 CRegKeySecurity_fnQueryInterface,
36 CRegKeySecurity_fnAddRef,
37 CRegKeySecurity_fnRelease,
38
39 /* CRegKeySecurity methods */
40 CRegKeySecurity_fnGetObjectInformation,
41 CRegKeySecurity_fnGetSecurity,
42 CRegKeySecurity_fnSetSecurity,
43 CRegKeySecurity_fnGetAccessRights,
44 CRegKeySecurity_fnMapGeneric,
45 CRegKeySecurity_fnGetInheritTypes,
46 CRegKeySecurity_fnPropertySheetPageCallback
47 };
48
49 SI_ACCESS RegAccess[] = {
50 {&GUID_NULL, KEY_ALL_ACCESS, (LPWSTR)MAKEINTRESOURCE(IDS_ACCESS_FULLCONTROL), SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC},
51 {&GUID_NULL, KEY_READ, (LPWSTR)MAKEINTRESOURCE(IDS_ACCESS_READ), SI_ACCESS_GENERAL},
52 {&GUID_NULL, KEY_QUERY_VALUE, (LPWSTR)MAKEINTRESOURCE(IDS_ACCESS_QUERYVALUE), SI_ACCESS_SPECIFIC},
53 {&GUID_NULL, KEY_SET_VALUE, (LPWSTR)MAKEINTRESOURCE(IDS_ACCESS_SETVALUE), SI_ACCESS_SPECIFIC},
54 {&GUID_NULL, KEY_CREATE_SUB_KEY, (LPWSTR)MAKEINTRESOURCE(IDS_ACCESS_CREATESUBKEY), SI_ACCESS_SPECIFIC},
55 {&GUID_NULL, KEY_ENUMERATE_SUB_KEYS, (LPWSTR)MAKEINTRESOURCE(IDS_ACCESS_ENUMERATESUBKEYS), SI_ACCESS_SPECIFIC},
56 {&GUID_NULL, KEY_NOTIFY, (LPWSTR)MAKEINTRESOURCE(IDS_ACCESS_NOTIFY), SI_ACCESS_SPECIFIC},
57 {&GUID_NULL, KEY_CREATE_LINK, (LPWSTR)MAKEINTRESOURCE(IDS_ACCESS_CREATELINK), SI_ACCESS_SPECIFIC},
58 {&GUID_NULL, DELETE, (LPWSTR)MAKEINTRESOURCE(IDS_ACCESS_DELETE), SI_ACCESS_SPECIFIC},
59 {&GUID_NULL, WRITE_DAC, (LPWSTR)MAKEINTRESOURCE(IDS_ACCESS_WRITEDAC), SI_ACCESS_SPECIFIC},
60 {&GUID_NULL, WRITE_OWNER, (LPWSTR)MAKEINTRESOURCE(IDS_ACCESS_WRITEOWNER), SI_ACCESS_SPECIFIC},
61 {&GUID_NULL, READ_CONTROL, (LPWSTR)MAKEINTRESOURCE(IDS_ACCESS_READCONTROL), SI_ACCESS_SPECIFIC},
62 };
63
64 DWORD RegDefaultAccess = 1; /* KEY_READ */
65
66 GENERIC_MAPPING RegAccessMasks = {
67 KEY_READ,
68 KEY_WRITE,
69 KEY_EXECUTE,
70 KEY_ALL_ACCESS
71 };
72
73 SI_INHERIT_TYPE RegInheritTypes[] = {
74 {&GUID_NULL, 0, (LPWSTR)MAKEINTRESOURCE(IDS_INHERIT_THISKEYONLY)},
75 {&GUID_NULL, CONTAINER_INHERIT_ACE, (LPWSTR)MAKEINTRESOURCE(IDS_INHERIT_THISKEYANDSUBKEYS)},
76 {&GUID_NULL, INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE, (LPWSTR)MAKEINTRESOURCE(IDS_INHERIT_SUBKEYSONLY)},
77 };
78
79
80 static LPREGKEYSECURITY CRegKeySecurity_fnConstructor(HANDLE Handle, SI_OBJECT_INFO *ObjectInfo, BOOL *Btn)
81 {
82 LPREGKEYSECURITY obj;
83
84 obj = (LPREGKEYSECURITY)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(REGKEYSECURITY));
85 if(obj != NULL)
86 {
87 obj->ref = 1;
88 obj->lpVtbl = &efvt;
89 obj->Handle = Handle;
90 obj->ObjectInfo = *ObjectInfo;
91 obj->Btn = Btn;
92 }
93
94 return obj;
95 }
96
97 HRESULT STDMETHODCALLTYPE
98 CRegKeySecurity_fnQueryInterface(LPREGKEYSECURITY this,
99 REFIID iid,
100 PVOID *pvObject)
101 {
102 if(IsEqualGUID(iid, &IID_IUnknown) ||
103 IsEqualGUID(iid, &IID_CRegKeySecurity))
104 {
105 *pvObject = this;
106 return S_OK;
107 }
108
109 *pvObject = NULL;
110 return E_NOINTERFACE;
111 }
112
113 ULONG STDMETHODCALLTYPE
114 CRegKeySecurity_fnAddRef(LPREGKEYSECURITY this)
115 {
116 return (ULONG)InterlockedIncrement((LONG*)&this->ref);
117 }
118
119 ULONG STDMETHODCALLTYPE
120 CRegKeySecurity_fnRelease(LPREGKEYSECURITY this)
121 {
122 ULONG rfc;
123
124 rfc = (ULONG)InterlockedDecrement((LONG*)&this->ref);
125 if(rfc == 0)
126 {
127 HeapFree(GetProcessHeap(), 0, this);
128 }
129 return rfc;
130 }
131
132 HRESULT STDMETHODCALLTYPE
133 CRegKeySecurity_fnGetObjectInformation(LPREGKEYSECURITY this,
134 PSI_OBJECT_INFO pObjectInfo)
135 {
136 *pObjectInfo = this->ObjectInfo;
137 return S_OK;
138 }
139
140 HRESULT STDMETHODCALLTYPE
141 CRegKeySecurity_fnGetSecurity(LPREGKEYSECURITY this,
142 SECURITY_INFORMATION RequestedInformation,
143 PSECURITY_DESCRIPTOR* ppSecurityDescriptor,
144 BOOL fDefault)
145 {
146 DWORD DescriptorSize = 0;
147 PSECURITY_DESCRIPTOR SecurityDescriptor;
148 LONG ErrorCode;
149
150 /* find out how much memory we need to allocate */
151 ErrorCode = RegGetKeySecurity(this->Handle, RequestedInformation, NULL, &DescriptorSize);
152 if(ErrorCode == ERROR_INSUFFICIENT_BUFFER)
153 {
154 SecurityDescriptor = (PSECURITY_DESCRIPTOR)LocalAlloc(LMEM_FIXED, DescriptorSize);
155 if (SecurityDescriptor != NULL)
156 {
157 if (RegGetKeySecurity(this->Handle, RequestedInformation, SecurityDescriptor, &DescriptorSize) == ERROR_SUCCESS)
158 {
159 *ppSecurityDescriptor = SecurityDescriptor;
160 return S_OK;
161 }
162 else
163 {
164 LocalFree((HLOCAL)SecurityDescriptor);
165 return E_ACCESSDENIED;
166 }
167 }
168 else
169 {
170 return E_OUTOFMEMORY;
171 }
172 }
173 else
174 {
175 return E_ACCESSDENIED;
176 }
177 }
178
179 HRESULT STDMETHODCALLTYPE
180 CRegKeySecurity_fnSetSecurity(LPREGKEYSECURITY this,
181 SECURITY_INFORMATION RequestedInformation,
182 PSECURITY_DESCRIPTOR pSecurityDescriptor)
183 {
184 /* FIXME */
185 *this->Btn = TRUE;
186 return S_OK;
187 }
188
189 HRESULT STDMETHODCALLTYPE
190 CRegKeySecurity_fnGetAccessRights(LPREGKEYSECURITY this,
191 const GUID* pguidObjectType,
192 DWORD dwFlags,
193 PSI_ACCESS* ppAccess,
194 ULONG* pcAccesses,
195 ULONG* piDefaultAccess)
196 {
197 *ppAccess = RegAccess;
198 *pcAccesses = sizeof(RegAccess) / sizeof(SI_ACCESS);
199 *piDefaultAccess = RegDefaultAccess;
200 return S_OK;
201 }
202
203 HRESULT STDMETHODCALLTYPE
204 CRegKeySecurity_fnMapGeneric(LPREGKEYSECURITY this,
205 const GUID* pguidObjectType,
206 UCHAR* pAceFlags,
207 ACCESS_MASK* pMask)
208 {
209 MapGenericMask(pMask, (PGENERIC_MAPPING)&RegAccessMasks);
210 *pMask &= ~SYNCHRONIZE;
211 return S_OK;
212 }
213
214 HRESULT STDMETHODCALLTYPE
215 CRegKeySecurity_fnGetInheritTypes(LPREGKEYSECURITY this,
216 PSI_INHERIT_TYPE* ppInheritTypes,
217 ULONG* pcInheritTypes)
218 {
219 /* FIXME */
220 if(this->ObjectInfo.dwFlags & SI_CONTAINER)
221 {
222 *ppInheritTypes = RegInheritTypes;
223 *pcInheritTypes = sizeof(RegInheritTypes) / sizeof(SI_INHERIT_TYPE);
224 return S_OK;
225 }
226 return E_NOTIMPL;
227 }
228
229 HRESULT STDMETHODCALLTYPE
230 CRegKeySecurity_fnPropertySheetPageCallback(LPREGKEYSECURITY this,
231 HWND hwnd,
232 UINT uMsg,
233 SI_PAGE_TYPE uPage)
234 {
235 /* FIXME */
236 return S_OK;
237 }
238
239
240 /******************************************************************************/
241
242 #define ACLUI_DLL _T("aclui.dll")
243 #define FN_EDITSECURITY "EditSecurity" /* no unicode, GetProcAddr doesn't accept unicode! */
244
245 typedef struct _CHANGE_CONTEXT
246 {
247 HKEY hKey;
248 LPTSTR KeyString;
249 } CHANGE_CONTEXT, *PCHANGE_CONTEXT;
250
251 typedef BOOL (WINAPI *PEDITSECURITY)(HWND hwndOwner,
252 LPREGKEYSECURITY psi);
253
254 static PEDITSECURITY pfnEditSecurity;
255 static HMODULE hAclUiDll;
256
257 BOOL
258 InitializeAclUiDll(VOID)
259 {
260 if(!(hAclUiDll = LoadLibrary(ACLUI_DLL)))
261 {
262 return FALSE;
263 }
264 if(!(pfnEditSecurity = (PEDITSECURITY)GetProcAddress(hAclUiDll, FN_EDITSECURITY)))
265 {
266 FreeLibrary(hAclUiDll);
267 hAclUiDll = NULL;
268 return FALSE;
269 }
270
271 return TRUE;
272 }
273
274 VOID
275 UnloadAclUiDll(VOID)
276 {
277 if(hAclUiDll != NULL)
278 {
279 FreeLibrary(hAclUiDll);
280 }
281 }
282
283 BOOL
284 RegKeyEditPermissions(HWND hWndOwner,
285 HKEY hKey,
286 LPCTSTR lpMachine,
287 LPCTSTR lpKeyName)
288 {
289 BOOL Result = FALSE;
290 LPWSTR Machine, KeyName;
291 HKEY hInfoKey;
292 LPREGKEYSECURITY RegKeySecurity;
293 SI_OBJECT_INFO ObjectInfo;
294
295 if(pfnEditSecurity == NULL)
296 {
297 return FALSE;
298 }
299
300 #ifndef UNICODE
301 /* aclui.dll only accepts unicode strings, convert them */
302 if(lpMachine != NULL)
303 {
304 int lnMachine = lstrlen(lpMachine);
305 if(!(Machine = HeapAlloc(GetProcessHeap(), 0, (lnMachine + 1) * sizeof(WCHAR))))
306 {
307 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
308 return FALSE;
309 }
310 if(lnMachine > 0)
311 {
312 MultiByteToWideChar(CP_ACP, 0, lpMachine, -1, Machine, lnMachine + 1);
313 }
314 else
315 *Machine = L'\0';
316 }
317 else
318 Machine = NULL;
319
320 if(lpKeyName != NULL)
321 {
322 int lnKeyName = lstrlen(lpKeyName);
323 if(!(KeyName = HeapAlloc(GetProcessHeap(), 0, (lnKeyName + 1) * sizeof(WCHAR))))
324 {
325 if(Machine != NULL)
326 {
327 HeapFree(GetProcessHeap(), 0, Machine);
328 }
329 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
330 return FALSE;
331 }
332 if(lnKeyName > 0)
333 {
334 MultiByteToWideChar(CP_ACP, 0, lpKeyName, -1, KeyName, lnKeyName + 1);
335 }
336 else
337 *KeyName = L'\0';
338 }
339 else
340 KeyName = NULL;
341 #else
342 Machine = (LPWSTR)lpMachine;
343 KeyName = (LPWSTR)lpKeyName;
344 #endif
345
346 /* try to open the key again with more access rights */
347 if(RegOpenKeyEx(hKey, NULL, 0, READ_CONTROL, &hInfoKey) != ERROR_SUCCESS)
348 {
349 /* FIXME - print error with FormatMessage */
350 return FALSE;
351 }
352
353 ObjectInfo.dwFlags = SI_EDIT_ALL | SI_ADVANCED | SI_CONTAINER | SI_OWNER_RECURSE | SI_EDIT_PERMS;
354 ObjectInfo.hInstance = hInst;
355 ObjectInfo.pszServerName = Machine;
356 ObjectInfo.pszObjectName = KeyName;
357 ObjectInfo.pszPageTitle = KeyName;
358
359 if(!(RegKeySecurity = CRegKeySecurity_fnConstructor(hInfoKey, &ObjectInfo, &Result)))
360 {
361 /* FIXME - print error with FormatMessage */
362 return FALSE;
363 }
364
365 /* display the security editor dialog */
366 pfnEditSecurity(hWndOwner, RegKeySecurity);
367
368 /* dereference the interface, it should be destroyed here */
369 CRegKeySecurity_fnRelease(RegKeySecurity);
370
371 RegCloseKey(hInfoKey);
372
373 #ifndef UNICODE
374 if(Machine != NULL)
375 {
376 HeapFree(GetProcessHeap(), 0, Machine);
377 }
378 if(KeyName != NULL)
379 {
380 HeapFree(GetProcessHeap(), 0, KeyName);
381 }
382 #endif
383
384 return Result;
385 }
386
387 /* EOF */