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