Merge 12736:14980 from trunk
[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 #define WIN32_LEAN_AND_MEAN /* Exclude rarely-used stuff from Windows headers */
22 #define INITGUID
23 #include <windows.h>
24 #include <tchar.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <accctrl.h>
28 #include <objbase.h>
29 #include <basetyps.h>
30 #include <unknwn.h>
31 #include "security.h"
32 #include "regproc.h"
33 #include "resource.h"
34
35 /******************************************************************************
36 Implementation of the CRegKeySecurity interface
37 ******************************************************************************/
38
39 static ifaceCRegKeySecurityVbtl efvt =
40 {
41 /* IUnknown methods */
42 CRegKeySecurity_fnQueryInterface,
43 CRegKeySecurity_fnAddRef,
44 CRegKeySecurity_fnRelease,
45
46 /* CRegKeySecurity methods */
47 CRegKeySecurity_fnGetObjectInformation,
48 CRegKeySecurity_fnGetSecurity,
49 CRegKeySecurity_fnSetSecurity,
50 CRegKeySecurity_fnGetAccessRights,
51 CRegKeySecurity_fnMapGeneric,
52 CRegKeySecurity_fnGetInheritTypes,
53 CRegKeySecurity_fnPropertySheetPageCallback
54 };
55
56 SI_ACCESS RegAccess[] = {
57 {&GUID_NULL, KEY_ALL_ACCESS, (LPWSTR)MAKEINTRESOURCE(IDS_ACCESS_FULLCONTROL), SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC},
58 {&GUID_NULL, KEY_READ, (LPWSTR)MAKEINTRESOURCE(IDS_ACCESS_READ), SI_ACCESS_GENERAL},
59 {&GUID_NULL, KEY_QUERY_VALUE, (LPWSTR)MAKEINTRESOURCE(IDS_ACCESS_QUERYVALUE), SI_ACCESS_SPECIFIC},
60 {&GUID_NULL, KEY_SET_VALUE, (LPWSTR)MAKEINTRESOURCE(IDS_ACCESS_SETVALUE), SI_ACCESS_SPECIFIC},
61 {&GUID_NULL, KEY_CREATE_SUB_KEY, (LPWSTR)MAKEINTRESOURCE(IDS_ACCESS_CREATESUBKEY), SI_ACCESS_SPECIFIC},
62 {&GUID_NULL, KEY_ENUMERATE_SUB_KEYS, (LPWSTR)MAKEINTRESOURCE(IDS_ACCESS_ENUMERATESUBKEYS), SI_ACCESS_SPECIFIC},
63 {&GUID_NULL, KEY_NOTIFY, (LPWSTR)MAKEINTRESOURCE(IDS_ACCESS_NOTIFY), SI_ACCESS_SPECIFIC},
64 {&GUID_NULL, KEY_CREATE_LINK, (LPWSTR)MAKEINTRESOURCE(IDS_ACCESS_CREATELINK), SI_ACCESS_SPECIFIC},
65 {&GUID_NULL, DELETE, (LPWSTR)MAKEINTRESOURCE(IDS_ACCESS_DELETE), SI_ACCESS_SPECIFIC},
66 {&GUID_NULL, WRITE_DAC, (LPWSTR)MAKEINTRESOURCE(IDS_ACCESS_WRITEDAC), SI_ACCESS_SPECIFIC},
67 {&GUID_NULL, WRITE_OWNER, (LPWSTR)MAKEINTRESOURCE(IDS_ACCESS_WRITEOWNER), SI_ACCESS_SPECIFIC},
68 {&GUID_NULL, READ_CONTROL, (LPWSTR)MAKEINTRESOURCE(IDS_ACCESS_READCONTROL), SI_ACCESS_SPECIFIC},
69 };
70
71 DWORD RegDefaultAccess = 1; /* KEY_READ */
72
73 GENERIC_MAPPING RegAccessMasks = {
74 KEY_READ,
75 KEY_WRITE,
76 KEY_EXECUTE,
77 KEY_ALL_ACCESS
78 };
79
80 SI_INHERIT_TYPE RegInheritTypes[] = {
81 {&GUID_NULL, 0, (LPWSTR)MAKEINTRESOURCE(IDS_INHERIT_THISKEYONLY)},
82 {&GUID_NULL, CONTAINER_INHERIT_ACE, (LPWSTR)MAKEINTRESOURCE(IDS_INHERIT_THISKEYANDSUBKEYS)},
83 {&GUID_NULL, INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE, (LPWSTR)MAKEINTRESOURCE(IDS_INHERIT_SUBKEYSONLY)},
84 };
85
86
87 LPREGKEYSECURITY CRegKeySecurity_fnConstructor(HANDLE Handle, SE_OBJECT_TYPE ObjectType, SI_OBJECT_INFO *ObjectInfo, BOOL *Btn)
88 {
89 LPREGKEYSECURITY obj;
90
91 obj = (LPREGKEYSECURITY)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(REGKEYSECURITY));
92 if(obj != NULL)
93 {
94 obj->ref = 1;
95 obj->lpVtbl = &efvt;
96 obj->Handle = Handle;
97 obj->ObjectType = ObjectType;
98 obj->ObjectInfo = *ObjectInfo;
99 obj->Btn = Btn;
100 }
101
102 return obj;
103 }
104
105 HRESULT STDMETHODCALLTYPE
106 CRegKeySecurity_fnQueryInterface(LPREGKEYSECURITY this,
107 REFIID iid,
108 PVOID *pvObject)
109 {
110 if(IsEqualGUID(iid, &IID_IUnknown) ||
111 IsEqualGUID(iid, &IID_CRegKeySecurity))
112 {
113 *pvObject = this;
114 return S_OK;
115 }
116
117 *pvObject = NULL;
118 return E_NOINTERFACE;
119 }
120
121 ULONG STDMETHODCALLTYPE
122 CRegKeySecurity_fnAddRef(LPREGKEYSECURITY this)
123 {
124 return (ULONG)InterlockedIncrement(&this->ref);
125 }
126
127 ULONG STDMETHODCALLTYPE
128 CRegKeySecurity_fnRelease(LPREGKEYSECURITY this)
129 {
130 ULONG rfc;
131
132 rfc = (ULONG)InterlockedDecrement(&this->ref);
133 if(rfc == 0)
134 {
135 HeapFree(GetProcessHeap(), 0, this);
136 }
137 return rfc;
138 }
139
140 HRESULT STDMETHODCALLTYPE
141 CRegKeySecurity_fnGetObjectInformation(LPREGKEYSECURITY this,
142 PSI_OBJECT_INFO pObjectInfo)
143 {
144 *pObjectInfo = this->ObjectInfo;
145 return S_OK;
146 }
147
148 HRESULT STDMETHODCALLTYPE
149 CRegKeySecurity_fnGetSecurity(LPREGKEYSECURITY this,
150 SECURITY_INFORMATION RequestedInformation,
151 PSECURITY_DESCRIPTOR* ppSecurityDescriptor,
152 BOOL fDefault)
153 {
154 /* FIXME */
155 if(GetSecurityInfo(this->Handle, this->ObjectType, RequestedInformation, 0, 0,
156 0, 0, ppSecurityDescriptor) == ERROR_SUCCESS)
157 {
158 return S_OK;
159 }
160 else
161 {
162 return E_ACCESSDENIED;
163 }
164 }
165
166 HRESULT STDMETHODCALLTYPE
167 CRegKeySecurity_fnSetSecurity(LPREGKEYSECURITY this,
168 SECURITY_INFORMATION RequestedInformation,
169 PSECURITY_DESCRIPTOR pSecurityDescriptor)
170 {
171 /* FIXME */
172 *this->Btn = TRUE;
173 return S_OK;
174 }
175
176 HRESULT STDMETHODCALLTYPE
177 CRegKeySecurity_fnGetAccessRights(LPREGKEYSECURITY this,
178 const GUID* pguidObjectType,
179 DWORD dwFlags,
180 PSI_ACCESS* ppAccess,
181 ULONG* pcAccesses,
182 ULONG* piDefaultAccess)
183 {
184 *ppAccess = RegAccess;
185 *pcAccesses = sizeof(RegAccess) / sizeof(SI_ACCESS);
186 *piDefaultAccess = RegDefaultAccess;
187 return S_OK;
188 }
189
190 HRESULT STDMETHODCALLTYPE
191 CRegKeySecurity_fnMapGeneric(LPREGKEYSECURITY this,
192 const GUID* pguidObjectType,
193 UCHAR* pAceFlags,
194 ACCESS_MASK* pMask)
195 {
196 MapGenericMask(pMask, (PGENERIC_MAPPING)&RegAccessMasks);
197 *pMask &= ~SYNCHRONIZE;
198 return S_OK;
199 }
200
201 HRESULT STDMETHODCALLTYPE
202 CRegKeySecurity_fnGetInheritTypes(LPREGKEYSECURITY this,
203 PSI_INHERIT_TYPE* ppInheritTypes,
204 ULONG* pcInheritTypes)
205 {
206 /* FIXME */
207 if(this->ObjectInfo.dwFlags & SI_CONTAINER)
208 {
209 *ppInheritTypes = RegInheritTypes;
210 *pcInheritTypes = sizeof(RegInheritTypes) / sizeof(SI_INHERIT_TYPE);
211 return S_OK;
212 }
213 return E_NOTIMPL;
214 }
215
216 HRESULT STDMETHODCALLTYPE
217 CRegKeySecurity_fnPropertySheetPageCallback(LPREGKEYSECURITY this,
218 HWND hwnd,
219 UINT uMsg,
220 SI_PAGE_TYPE uPage)
221 {
222 /* FIXME */
223 return S_OK;
224 }
225
226
227 /******************************************************************************/
228
229 #define ACLUI_DLL _T("aclui.dll")
230 #define FN_EDITSECURITY "EditSecurity" /* no unicode, GetProcAddr doesn't accept unicode! */
231
232 typedef struct _CHANGE_CONTEXT
233 {
234 HKEY hKey;
235 LPTSTR KeyString;
236 } CHANGE_CONTEXT, *PCHANGE_CONTEXT;
237
238 typedef BOOL (WINAPI *PEDITSECURITY)(HWND hwndOwner,
239 LPREGKEYSECURITY psi);
240
241 static PEDITSECURITY pfnEditSecurity;
242 static HMODULE hAclUiDll;
243
244 BOOL
245 InitializeAclUiDll(VOID)
246 {
247 if(!(hAclUiDll = LoadLibrary(ACLUI_DLL)))
248 {
249 return FALSE;
250 }
251 if(!(pfnEditSecurity = (PEDITSECURITY)GetProcAddress(hAclUiDll, FN_EDITSECURITY)))
252 {
253 FreeLibrary(hAclUiDll);
254 hAclUiDll = NULL;
255 return FALSE;
256 }
257
258 return TRUE;
259 }
260
261 VOID
262 UnloadAclUiDll(VOID)
263 {
264 if(hAclUiDll != NULL)
265 {
266 FreeLibrary(hAclUiDll);
267 }
268 }
269
270 BOOL
271 RegKeyEditPermissions(HWND hWndOwner,
272 HKEY hKey,
273 LPCTSTR lpMachine,
274 LPCTSTR lpKeyName)
275 {
276 BOOL Result;
277 LPWSTR Machine, KeyName;
278 HKEY hInfoKey;
279 LPREGKEYSECURITY RegKeySecurity;
280 SI_OBJECT_INFO ObjectInfo;
281
282 if(pfnEditSecurity == NULL)
283 {
284 return FALSE;
285 }
286
287 #ifndef UNICODE
288 /* aclui.dll only accepts unicode strings, convert them */
289 if(lpMachine != NULL)
290 {
291 int lnMachine = lstrlen(lpMachine);
292 if(!(Machine = HeapAlloc(GetProcessHeap(), 0, (lnMachine + 1) * sizeof(WCHAR))))
293 {
294 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
295 return FALSE;
296 }
297 if(lnMachine > 0)
298 {
299 MultiByteToWideChar(CP_ACP, 0, lpMachine, -1, Machine, lnMachine + 1);
300 }
301 else
302 *Machine = L'\0';
303 }
304 else
305 Machine = NULL;
306
307 if(lpKeyName != NULL)
308 {
309 int lnKeyName = lstrlen(lpKeyName);
310 if(!(KeyName = HeapAlloc(GetProcessHeap(), 0, (lnKeyName + 1) * sizeof(WCHAR))))
311 {
312 if(Machine != NULL)
313 {
314 HeapFree(GetProcessHeap(), 0, Machine);
315 }
316 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
317 return FALSE;
318 }
319 if(lnKeyName > 0)
320 {
321 MultiByteToWideChar(CP_ACP, 0, lpKeyName, -1, KeyName, lnKeyName + 1);
322 }
323 else
324 *KeyName = L'\0';
325 }
326 else
327 KeyName = NULL;
328 #else
329 Machine = (LPWSTR)lpMachine;
330 KeyName = (LPWSTR)lpKeyName;
331 #endif
332
333 /* try to open the key again with more access rights */
334 if(RegOpenKeyEx(hKey, NULL, 0, READ_CONTROL, &hInfoKey) != ERROR_SUCCESS)
335 {
336 /* FIXME - print error with FormatMessage */
337 return FALSE;
338 }
339
340 ObjectInfo.dwFlags = SI_EDIT_ALL | SI_ADVANCED | SI_CONTAINER | SI_OWNER_RECURSE | SI_EDIT_PERMS;
341 ObjectInfo.hInstance = hInst;
342 ObjectInfo.pszServerName = Machine;
343 ObjectInfo.pszObjectName = KeyName;
344 ObjectInfo.pszPageTitle = KeyName;
345
346 if(!(RegKeySecurity = CRegKeySecurity_fnConstructor(hInfoKey, SE_REGISTRY_KEY, &ObjectInfo, &Result)))
347 {
348 /* FIXME - print error with FormatMessage */
349 return FALSE;
350 }
351
352 /* display the security editor dialog */
353 pfnEditSecurity(hWndOwner, RegKeySecurity);
354
355 /* dereference the interface, it should be destroyed here */
356 CRegKeySecurity_fnRelease(RegKeySecurity);
357
358 RegCloseKey(hInfoKey);
359
360 #ifndef UNICODE
361 if(Machine != NULL)
362 {
363 HeapFree(GetProcessHeap(), 0, Machine);
364 }
365 if(KeyName != NULL)
366 {
367 HeapFree(GetProcessHeap(), 0, KeyName);
368 }
369 #endif
370
371 return Result;
372 }
373
374 /* EOF */