c4da5db0750fadde2f34dc4cadac0a4315ca730f
[reactos.git] / rosapps / applications / sysutils / regexpl / ShellCommandSACL.cpp
1 /* $Id$
2 *
3 * regexpl - Console Registry Explorer
4 *
5 * Copyright (C) 2000-2005 Nedko Arnaudov <nedko@users.sourceforge.net>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; see the file COPYING. If not, write to
19 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
21 */
22
23 // ShellCommandSACL.cpp: implementation of the CShellCommandSACL class.
24 //
25 //////////////////////////////////////////////////////////////////////
26
27 #include "ph.h"
28 #include "ShellCommandSACL.h"
29 #include "RegistryExplorer.h"
30 #include "SecurityDescriptor.h"
31
32 #define SACL_CMD _T("SACL")
33 #define SACL_CMD_LENGTH COMMAND_LENGTH(SACL_CMD)
34 #define SACL_CMD_SHORT_DESC SACL_CMD _T(" command is used to view")/*"/edit"*/_T(" key's SACL.\n")
35
36 //////////////////////////////////////////////////////////////////////
37 // Construction/Destruction
38 //////////////////////////////////////////////////////////////////////
39
40 CShellCommandSACL::CShellCommandSACL(CRegistryTree& rTree):m_rTree(rTree)
41 {
42
43 }
44
45 CShellCommandSACL::~CShellCommandSACL()
46 {
47
48 }
49
50 BOOL CShellCommandSACL::Match(const TCHAR *pchCommand)
51 {
52 if (_tcsicmp(pchCommand,SACL_CMD) == 0)
53 return TRUE;
54 if (_tcsnicmp(pchCommand,SACL_CMD _T(".."),SACL_CMD_LENGTH+2*sizeof(TCHAR)) == 0)
55 return TRUE;
56 if (_tcsnicmp(pchCommand,SACL_CMD _T("/") ,SACL_CMD_LENGTH+1*sizeof(TCHAR)) == 0)
57 return TRUE;
58 if (_tcsnicmp(pchCommand,SACL_CMD _T("\\"),SACL_CMD_LENGTH+1*sizeof(TCHAR)) == 0)
59 return TRUE;
60 return FALSE;
61 }
62
63 int CShellCommandSACL::Execute(CConsole &rConsole, CArgumentParser& rArguments)
64 {
65 #define ERROR_MSG_BUFFER_SIZE 1024
66 TCHAR pszError_msg[ERROR_MSG_BUFFER_SIZE];
67 pszError_msg[ERROR_MSG_BUFFER_SIZE-1] = 0;
68
69 rArguments.ResetArgumentIteration();
70
71 const TCHAR *pszKey = NULL;
72 BOOL blnDo = TRUE;
73 BOOL blnBadParameter = FALSE;
74 BOOL blnHelp = FALSE;
75 const TCHAR *pszParameter;
76 const TCHAR *pszCommandItself = rArguments.GetNextArgument();
77 DWORD dwError;
78 PISECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
79 CSecurityDescriptor sd;
80 HANDLE hThreadToken = INVALID_HANDLE_VALUE;
81
82 if ((_tcsnicmp(pszCommandItself,SACL_CMD _T(".."),SACL_CMD_LENGTH+2*sizeof(TCHAR)) == 0)||
83 (_tcsnicmp(pszCommandItself,SACL_CMD _T("\\"),SACL_CMD_LENGTH+1*sizeof(TCHAR)) == 0))
84 {
85 pszKey = pszCommandItself + SACL_CMD_LENGTH;
86 }
87 else if (_tcsnicmp(pszCommandItself,SACL_CMD _T("/"),SACL_CMD_LENGTH+1*sizeof(TCHAR)) == 0)
88 {
89 pszParameter = pszCommandItself + SACL_CMD_LENGTH;
90 goto CheckSACLArgument;
91 }
92
93 while((pszParameter = rArguments.GetNextArgument()) != NULL)
94 {
95 CheckSACLArgument:
96 blnBadParameter = FALSE;
97 if ((_tcsicmp(pszParameter,_T("/?")) == 0)||
98 (_tcsicmp(pszParameter,_T("-?")) == 0))
99 {
100 blnHelp = TRUE;
101 blnDo = pszKey != NULL;
102 }
103 else if (!pszKey)
104 {
105 pszKey = pszParameter;
106 blnDo = TRUE;
107 }
108 else
109 {
110 blnBadParameter = TRUE;
111 }
112 if (blnBadParameter)
113 {
114 rConsole.Write(_T("Bad parameter: "));
115 rConsole.Write(pszParameter);
116 rConsole.Write(_T("\n"));
117 }
118 }
119
120 CRegistryKey Key;
121
122 ASSERT(hThreadToken == INVALID_HANDLE_VALUE);
123
124 // Open thread token
125 if (!OpenThreadToken(GetCurrentThread(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,FALSE,&hThreadToken))
126 { // OpenThreadToken failed
127 dwError = GetLastError();
128 if (dwError != ERROR_NO_TOKEN)
129 {
130 _sntprintf(pszError_msg,ERROR_MSG_BUFFER_SIZE-1,_T("\nCannot open thread token.\nOpenThreadToken fails with error: %u\n"),(unsigned int)dwError);
131 goto Error;
132 }
133
134 // If the thread does not have an access token, we'll examine the
135 // access token associated with the process.
136 if (!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hThreadToken))
137 {
138 _sntprintf(pszError_msg,ERROR_MSG_BUFFER_SIZE-1,_T("\nCannot open process token.\nOpenProcessToken fails with error: %u\n"),(unsigned int)GetLastError());
139 goto Error;
140 }
141 }
142
143 ASSERT(hThreadToken != INVALID_HANDLE_VALUE);
144
145 // enable SeSecurityPrivilege privilege
146 TOKEN_PRIVILEGES priv;
147 priv.PrivilegeCount = 1;
148 priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
149 if (!LookupPrivilegeValue(
150 NULL, // lookup privilege on local system
151 SE_SECURITY_NAME, // privilege to lookup
152 &(priv.Privileges[0].Luid))) // receives LUID of privilege
153 {
154 _sntprintf(pszError_msg,ERROR_MSG_BUFFER_SIZE-1,_T("\nCannot retrieve the locally unique identifier for %s privilege.\nLookupPrivilegeValue error: %u\n"),SE_SECURITY_NAME,(unsigned int)GetLastError());
155 goto Error;
156 }
157
158 BOOL blnAdjRet;
159 blnAdjRet = AdjustTokenPrivileges(
160 hThreadToken,
161 FALSE,
162 &priv,
163 sizeof(TOKEN_PRIVILEGES),
164 (PTOKEN_PRIVILEGES)NULL,
165 (PDWORD)NULL);
166 dwError = GetLastError();
167 if (!blnAdjRet)
168 {
169 _sntprintf(pszError_msg,ERROR_MSG_BUFFER_SIZE-1,_T("\nCannot enable %s privilege.\nAdjustTokenPrivileges fails with error: %u%s\n"),SE_SECURITY_NAME,(unsigned int)dwError,(dwError == 5)?_T(" (Access denied)"):_T(""));
170 goto Error;
171 }
172
173 if (dwError != ERROR_SUCCESS)
174 {
175 if (dwError == ERROR_NOT_ALL_ASSIGNED)
176 {
177 _sntprintf(pszError_msg,ERROR_MSG_BUFFER_SIZE-1,_T("\nCannot enable %s privilege.\nThe token does not have the %s privilege\n"),SE_SECURITY_NAME,SE_SECURITY_NAME);
178 }
179 else
180 {
181 _sntprintf(pszError_msg,ERROR_MSG_BUFFER_SIZE-1,_T("\nCannot enable %s privilege.\nAdjustTokenPrivileges succeds with error: %u\n"),SE_SECURITY_NAME,(unsigned int)dwError);
182 }
183
184 goto Error;
185 }
186
187 if (!m_rTree.GetKey(pszKey?pszKey:_T("."),KEY_QUERY_VALUE|READ_CONTROL|ACCESS_SYSTEM_SECURITY,Key))
188 {
189 rConsole.Write(m_rTree.GetLastErrorDescription());
190 blnDo = FALSE;
191 }
192
193 if (blnHelp)
194 {
195 rConsole.Write(GetHelpString());
196 }
197
198 if (blnDo&&blnHelp)
199 rConsole.Write(_T("\n"));
200
201 if (!blnDo)
202 return 0;
203
204 if (Key.IsRoot())
205 {
206 _tcsncpy(pszError_msg,SACL_CMD COMMAND_NA_ON_ROOT,ERROR_MSG_BUFFER_SIZE-1);
207 goto Error;
208 }
209
210 DWORD dwSecurityDescriptorLength;
211 rConsole.Write(_T("Key : "));
212 rConsole.Write(_T("\\"));
213
214 rConsole.Write(Key.GetKeyName());
215 rConsole.Write(_T("\n"));
216 dwError = Key.GetSecurityDescriptorLength(&dwSecurityDescriptorLength);
217 if (dwError != ERROR_SUCCESS)
218 {
219 _sntprintf(pszError_msg,ERROR_MSG_BUFFER_SIZE-1,_T("\nCannot get security descriptor's length for current key.\nError: %u\n"),(unsigned int)dwError);
220 goto Error;
221 }
222
223 pSecurityDescriptor = (PISECURITY_DESCRIPTOR) new unsigned char [dwSecurityDescriptorLength];
224 if (!pSecurityDescriptor)
225 {
226 _tcsncpy(pszError_msg,_T("\nOut of memory.\n"),ERROR_MSG_BUFFER_SIZE-1);
227 goto Error;
228 }
229
230 DWORD dwSecurityDescriptorLength1;
231 dwSecurityDescriptorLength1 = dwSecurityDescriptorLength;
232 dwError = Key.GetSecurityDescriptor((SECURITY_INFORMATION)SACL_SECURITY_INFORMATION,pSecurityDescriptor,&dwSecurityDescriptorLength1);
233 if (dwError != ERROR_SUCCESS)
234 {
235 _sntprintf(pszError_msg,ERROR_MSG_BUFFER_SIZE-1,_T("\nCannot get security descriptor for current key.\nError: %u%s\n"),(unsigned int)dwError,(dwError == 1314)?_T("(A required privilege is not held by the client.)\n"):_T(""));
236 goto Error;
237 }
238
239 sd.AssociateDescriptor(pSecurityDescriptor);
240 sd.BeginSACLInteration();
241
242 if ((!sd.DescriptorContainsSACL())||(sd.HasNULLSACL()))
243 {
244 _tcsncpy(pszError_msg,_T("Key has not SACL.\n"),ERROR_MSG_BUFFER_SIZE-1);
245 goto Error;
246 }
247
248 if (!sd.HasValidSACL())
249 {
250 _tcsncpy(pszError_msg,_T("Invalid SACL.\n"),ERROR_MSG_BUFFER_SIZE-1);
251 goto Error;
252 }
253
254 DWORD nACECount;
255 nACECount = sd.GetSACLEntriesCount();
256 rConsole.Write(_T("SACL has "));
257 TCHAR Buffer[256];
258 rConsole.Write(_itoa(nACECount,Buffer,10));
259 rConsole.Write(_T(" ACEs.\n"));
260 ASSERT(sizeof(ACL) == 8);
261 rConsole.Write(_T("\n"));
262 for (DWORD i = 0 ; i < nACECount ; i++)
263 {
264 rConsole.Write(_T("\n"));
265 rConsole.Write(_T("\tACE Index: "));
266 rConsole.Write(_itoa(i,Buffer,10));
267 rConsole.Write(_T("\n"));
268 rConsole.Write(_T("\tAudit Type: "));
269 BOOL blnFailed, blnSuccessful;
270 if (sd.GetSACLEntry(i,blnFailed,blnSuccessful) != CSecurityDescriptor::SystemAudit)
271 {
272 rConsole.Write(_T("Unknown ACE type.\nCannot continue ACE list dump.\n"));
273 goto AbortDumpSACL;
274 }
275
276 if (blnFailed)
277 rConsole.Write(_T("Failed access"));
278
279 if (blnFailed && blnSuccessful)
280 rConsole.Write(_T(" & "));
281 if (blnSuccessful)
282 rConsole.Write(_T("Successful access"));
283 rConsole.Write(_T("\n"));
284
285 PSID pSID = sd.GetCurrentACE_SID();
286 if ((pSID == NULL)||(!IsValidSid(pSID)))
287 {
288 rConsole.Write(_T("\tInvalid SID.\n"));
289 }
290
291 DWORD dwSIDStringSize = 0;
292 BOOL blnRet = GetTextualSid(pSID,NULL,&dwSIDStringSize);
293 ASSERT(!blnRet);
294 ASSERT(GetLastError() == ERROR_INSUFFICIENT_BUFFER);
295 TCHAR *pszSID = new TCHAR[dwSIDStringSize];
296
297 if (!pszSID)
298 {
299 _tcsncpy(pszError_msg,_T("\nOut of memory.\n"),ERROR_MSG_BUFFER_SIZE-1);
300 goto Error;
301 }
302
303 if(!GetTextualSid(pSID,pszSID,&dwSIDStringSize))
304 {
305 dwError = GetLastError();
306 ASSERT(dwError != ERROR_INSUFFICIENT_BUFFER);
307 rConsole.Write(_T("Error "));
308 TCHAR Buffer[256];
309 rConsole.Write(_itoa(dwError,Buffer,10));
310 rConsole.Write(_T("\nGetting string representation of SID\n"));
311 }
312 else
313 {
314 rConsole.Write(_T("\tSID: "));
315 rConsole.Write(pszSID);
316 rConsole.Write(_T("\n"));
317 }
318 delete pszSID;
319
320 TCHAR *pszName, *pszDomainName;
321 DWORD dwNameBufferLength, dwDomainNameBufferLength;
322 dwNameBufferLength = 1024;
323 dwDomainNameBufferLength = 1024;
324
325 pszName = new TCHAR [dwNameBufferLength];
326 if (!pszName)
327 {
328 _tcsncpy(pszError_msg,_T("\nOut of memory.\n"),ERROR_MSG_BUFFER_SIZE-1);
329 goto Error;
330 }
331
332 pszDomainName = new TCHAR [dwDomainNameBufferLength];
333 if (!pszDomainName)
334 {
335 _tcsncpy(pszError_msg,_T("\nOut of memory.\n"),ERROR_MSG_BUFFER_SIZE-1);
336 goto Error;
337 }
338
339 DWORD dwNameLength = dwNameBufferLength, dwDomainNameLength = dwDomainNameBufferLength;
340 SID_NAME_USE Use;
341 if (!LookupAccountSid(NULL,pSID,pszName,&dwNameLength,pszDomainName,&dwDomainNameLength,&Use))
342 {
343 rConsole.Write(_T("Error "));
344 TCHAR Buffer[256];
345 rConsole.Write(_itoa(GetLastError(),Buffer,10));
346 rConsole.Write(_T("\n"));
347 }
348 else
349 {
350 rConsole.Write(_T("\tTrustee Domain: "));
351 rConsole.Write(pszDomainName);
352 rConsole.Write(_T("\n"));
353 rConsole.Write(_T("\tTrustee Name: "));
354 rConsole.Write(pszName);
355 rConsole.Write(_T("\n\tSID type: "));
356 rConsole.Write(GetSidTypeName(Use));
357 rConsole.Write(_T("\n"));
358 }
359 DWORD dwAccessMask;
360 sd.GetCurrentACE_AccessMask(dwAccessMask);
361 wsprintf(Buffer,_T("\tAccess Mask: 0x%08lX\n"),dwAccessMask);
362 rConsole.Write(Buffer);
363 if (dwAccessMask & GENERIC_READ)
364 {
365 rConsole.Write(_T("\t\tGENERIC_READ\n"));
366 }
367 if (dwAccessMask & GENERIC_WRITE)
368 {
369 rConsole.Write(_T("\t\tGENERIC_WRITE\n"));
370 }
371 if (dwAccessMask & GENERIC_EXECUTE)
372 {
373 rConsole.Write(_T("\t\tGENERIC_EXECUTE\n"));
374 }
375 if (dwAccessMask & GENERIC_ALL)
376 {
377 rConsole.Write(_T("\t\tGENERIC_ALL\n"));
378 }
379 if (dwAccessMask & SYNCHRONIZE)
380 {
381 rConsole.Write(_T("\t\tSYNCHRONIZE\n"));
382 }
383 if (dwAccessMask & WRITE_OWNER)
384 {
385 rConsole.Write(_T("\t\tWRITE_OWNER\n"));
386 }
387 if (dwAccessMask & WRITE_DAC)
388 {
389 rConsole.Write(_T("\t\tWRITE_DAC\n"));
390 }
391 if (dwAccessMask & READ_CONTROL)
392 {
393 rConsole.Write(_T("\t\tREAD_CONTROL\n"));
394 }
395 if (dwAccessMask & DELETE)
396 {
397 rConsole.Write(_T("\t\tDELETE\n"));
398 }
399 if (dwAccessMask & KEY_CREATE_LINK)
400 {
401 rConsole.Write(_T("\t\tKEY_CREATE_LINK\n"));
402 }
403 if (dwAccessMask & KEY_NOTIFY)
404 {
405 rConsole.Write(_T("\t\tKEY_NOTIFY\n"));
406 }
407 if (dwAccessMask & KEY_ENUMERATE_SUB_KEYS)
408 {
409 rConsole.Write(_T("\t\tKEY_ENUMERATE_SUB_KEYS\n"));
410 }
411 if (dwAccessMask & KEY_CREATE_SUB_KEY)
412 {
413 rConsole.Write(_T("\t\tKEY_CREATE_SUB_KEY\n"));
414 }
415 if (dwAccessMask & KEY_SET_VALUE)
416 {
417 rConsole.Write(_T("\t\tKEY_SET_VALUE\n"));
418 }
419 if (dwAccessMask & KEY_QUERY_VALUE)
420 {
421 rConsole.Write(_T("\t\tKEY_QUERY_VALUE\n"));
422 }
423 } // for
424
425 AbortDumpSACL:
426 ASSERT(pSecurityDescriptor);
427 delete pSecurityDescriptor;
428
429 VERIFY(CloseHandle(hThreadToken));
430
431 return 0;
432 Error:
433 if (pSecurityDescriptor)
434 delete pSecurityDescriptor;
435
436 if (hThreadToken != INVALID_HANDLE_VALUE)
437 VERIFY(CloseHandle(hThreadToken));
438
439 rConsole.Write(pszError_msg);
440 return 0;
441 }
442
443 const TCHAR * CShellCommandSACL::GetHelpString()
444 {
445 return SACL_CMD_SHORT_DESC
446 _T("Syntax: ") SACL_CMD _T(" [<KEY>] [/?]\n\n")
447 _T(" <KEY> - Optional relative path of desired key.\n")
448 _T(" /? - This help.\n\n")
449 _T("Without parameters, command displays SACL of current key.\n");
450 }
451
452 const TCHAR * CShellCommandSACL::GetHelpShortDescriptionString()
453 {
454 return SACL_CMD_SHORT_DESC;
455 }