bd80df9735efe5c6743013b0950ddce5b242a672
[reactos.git] / rosapps / sysutils / regexpl / ShellCommandSACL.cpp
1 /* $Id: ShellCommandSACL.cpp,v 1.1 2000/10/04 21:04:31 ea Exp $
2 *
3 * regexpl - Console Registry Explorer
4 *
5 * Copyright (c) 1999-2000 Nedko Arnaoudov <nedkohome@atia.com>
6 *
7 * License: GNU GPL
8 *
9 */
10
11 // ShellCommandSACL.cpp: implementation of the CShellCommandSACL class.
12 //
13 //////////////////////////////////////////////////////////////////////
14
15 #include "ph.h"
16 #include "ShellCommandSACL.h"
17 #include "RegistryExplorer.h"
18 #include "SecurityDescriptor.h"
19
20 #define SACL_CMD _T("SACL")
21 #define SACL_CMD_LENGTH COMMAND_LENGTH(SACL_CMD)
22 #define SACL_CMD_SHORT_DESC SACL_CMD _T(" command is used to view")/*"/edit"*/_T(" key's SACL.\n")
23
24 //////////////////////////////////////////////////////////////////////
25 // Construction/Destruction
26 //////////////////////////////////////////////////////////////////////
27
28 CShellCommandSACL::CShellCommandSACL(CRegistryTree& rTree):m_rTree(rTree)
29 {
30
31 }
32
33 CShellCommandSACL::~CShellCommandSACL()
34 {
35
36 }
37
38 BOOL CShellCommandSACL::Match(const TCHAR *pchCommand)
39 {
40 if (_tcsicmp(pchCommand,SACL_CMD) == 0)
41 return TRUE;
42 if (_tcsnicmp(pchCommand,SACL_CMD _T(".."),SACL_CMD_LENGTH+2*sizeof(TCHAR)) == 0)
43 return TRUE;
44 if (_tcsnicmp(pchCommand,SACL_CMD _T("/") ,SACL_CMD_LENGTH+1*sizeof(TCHAR)) == 0)
45 return TRUE;
46 if (_tcsnicmp(pchCommand,SACL_CMD _T("\\"),SACL_CMD_LENGTH+1*sizeof(TCHAR)) == 0)
47 return TRUE;
48 return FALSE;
49 }
50
51 int CShellCommandSACL::Execute(CConsole &rConsole, CArgumentParser& rArguments)
52 {
53 TCHAR err_msg[1024];
54
55 rArguments.ResetArgumentIteration();
56
57 const TCHAR *pchKey = NULL;
58 BOOL blnDo = TRUE;
59 BOOL blnBadParameter = FALSE;
60 BOOL blnHelp = FALSE;
61 const TCHAR *pchParameter;
62 const TCHAR *pchCommandItself = rArguments.GetNextArgument();
63 DWORD dwError;
64
65 if ((_tcsnicmp(pchCommandItself,SACL_CMD _T(".."),SACL_CMD_LENGTH+2*sizeof(TCHAR)) == 0)||
66 (_tcsnicmp(pchCommandItself,SACL_CMD _T("\\"),SACL_CMD_LENGTH+1*sizeof(TCHAR)) == 0))
67 {
68 pchKey = pchCommandItself + SACL_CMD_LENGTH;
69 }
70 else if (_tcsnicmp(pchCommandItself,SACL_CMD _T("/"),SACL_CMD_LENGTH+1*sizeof(TCHAR)) == 0)
71 {
72 pchParameter = pchCommandItself + SACL_CMD_LENGTH;
73 goto CheckSACLArgument;
74 }
75
76 while((pchParameter = rArguments.GetNextArgument()) != NULL)
77 {
78 CheckSACLArgument:
79 blnBadParameter = FALSE;
80 // Console.Write(_T("Processing parameter: \")");
81 // Console.Write(pchParameter);
82 // Console.Write(_T("\")\n");
83 if ((_tcsicmp(pchParameter,_T("/?")) == 0)
84 ||(_tcsicmp(pchParameter,_T("-?")) == 0))
85 {
86 blnHelp = TRUE;
87 blnDo = pchKey != NULL;
88 }
89 else if (!pchKey)
90 {
91 pchKey = pchParameter;
92 blnDo = TRUE;
93 }
94 else
95 {
96 blnBadParameter = TRUE;
97 }
98 if (blnBadParameter)
99 {
100 rConsole.Write(_T("Bad parameter: "));
101 rConsole.Write(pchParameter);
102 rConsole.Write(_T("\n"));
103 }
104 }
105
106 CRegistryTree *pTree = NULL;
107 CRegistryKey *pKey = NULL;
108 if (pchKey)
109 {
110 pTree = new CRegistryTree(m_rTree);
111 if ((_tcscmp(pTree->GetCurrentPath(),m_rTree.GetCurrentPath()) != 0)||(!pTree->ChangeCurrentKey(pchKey)))
112 {
113 rConsole.Write(_T("Cannot open key "));
114 rConsole.Write(pchKey);
115 rConsole.Write(_T("\n"));
116 //blnHelp = TRUE;
117 blnDo = FALSE;
118 }
119 else
120 {
121 pKey = pTree->GetCurrentKey();
122 }
123 }
124 else
125 {
126 pKey = m_rTree.GetCurrentKey();
127 }
128
129 if (blnHelp)
130 {
131 rConsole.Write(GetHelpString());
132 }
133
134 if (blnDo&&blnHelp) rConsole.Write(_T("\n"));
135
136 if (blnDo)
137 {
138 try
139 {
140 if (!pKey)
141 throw (SACL_CMD COMMAND_NA_ON_ROOT);
142
143 HANDLE hThreadToken = INVALID_HANDLE_VALUE;
144 if (!OpenThreadToken(GetCurrentThread(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,FALSE,&hThreadToken))
145 { // OpenThreadToken fails
146 dwError = GetLastError();
147 if (dwError != ERROR_NO_TOKEN)
148 {
149 _stprintf(err_msg,_T("\nCannot open thread token.\nOpenThreadToken fails with error: %u\n"),dwError);
150 throw err_msg;
151 }
152 // If the thread does not have an access token, we'll examine the
153 // access token associated with the process.
154 if (!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hThreadToken))
155 {
156 _stprintf(err_msg,_T("\nCannot open process token.\nOpenProcessToken fails with error: %u\n"),GetLastError());
157 throw err_msg;
158 }
159 }
160 ASSERT(hThreadToken != INVALID_HANDLE_VALUE);
161 TOKEN_PRIVILEGES priv;
162 priv.PrivilegeCount = 1;
163 priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
164 if (!LookupPrivilegeValue(
165 NULL, // lookup privilege on local system
166 SE_SECURITY_NAME, // privilege to lookup
167 &(priv.Privileges[0].Luid))) // receives LUID of privilege
168 {
169 _stprintf(err_msg,_T("\nCannot retrieve the locally unique identifier for %s privilege.\nLookupPrivilegeValue error: %u\n"),SE_SECURITY_NAME,GetLastError());
170 throw err_msg;
171 }
172 BOOL blnAdjRet = AdjustTokenPrivileges(
173 hThreadToken,
174 FALSE,
175 &priv,
176 sizeof(TOKEN_PRIVILEGES),
177 (PTOKEN_PRIVILEGES)NULL,
178 (PDWORD)NULL);
179 dwError = GetLastError();
180 if (!blnAdjRet)
181 {
182 _stprintf(err_msg,_T("\nCannot enable %s privilege.\nAdjustTokenPrivileges fails with error: %u%s\n"),SE_SECURITY_NAME,dwError,(dwError == 5)?_T(" (Access denied)"):_T(""));
183 throw err_msg;
184 }
185 if (dwError != ERROR_SUCCESS)
186 {
187 if (dwError == ERROR_NOT_ALL_ASSIGNED)
188 {
189 _stprintf(err_msg,_T("\nCannot enable %s privilege.\nThe token does not have the %s privilege\n"),SE_SECURITY_NAME,SE_SECURITY_NAME);
190 }
191 else
192 {
193 _stprintf(err_msg,_T("\nCannot enable %s privilege.\nAdjustTokenPrivileges succeds with error: %u\n"),SE_SECURITY_NAME,dwError);
194 }
195 throw err_msg;
196 }
197 if (!pKey->IsPredefined())
198 {
199 dwError = pKey->Open(m_rTree.GetDesiredOpenKeyAccess()|ACCESS_SYSTEM_SECURITY);
200 if (dwError != ERROR_SUCCESS)
201 {
202 _stprintf(err_msg,_T("\nCannot reopen current key.\nError %u%s\n"),dwError,(dwError == 5)?_T(" (Access denied)"):_T(""));
203 throw err_msg;
204 }
205 }
206 DWORD dwSecurityDescriptorLength;
207 rConsole.Write(_T("Key : "));
208 rConsole.Write(_T("\\"));
209 rConsole.Write(pTree?pTree->GetCurrentPath():m_rTree.GetCurrentPath());
210 rConsole.Write(_T("\n"));
211 dwError = pKey->GetSecurityDescriptorLength(&dwSecurityDescriptorLength);
212 if (dwError != ERROR_SUCCESS)
213 {
214 _stprintf(err_msg,_T("\nCannot get security descriptor's length for current key.\nError: %u\n"),dwError);
215 throw err_msg;
216 }
217 PSECURITY_DESCRIPTOR pSecurityDescriptor = (PSECURITY_DESCRIPTOR) new unsigned char [dwSecurityDescriptorLength];
218 DWORD dwSecurityDescriptorLength1 = dwSecurityDescriptorLength;
219 dwError = pKey->GetSecurityDescriptor((SECURITY_INFORMATION)SACL_SECURITY_INFORMATION,pSecurityDescriptor,&dwSecurityDescriptorLength1);
220 if (dwError != ERROR_SUCCESS)
221 {
222 _stprintf(err_msg,_T("\nCannot get security descriptor for current key.\nError: %u%s\n"),dwError,(dwError == 1314)?_T("(A required privilege is not held by the client.)\n"):_T(""));
223 throw err_msg;
224 }
225 CSecurityDescriptor sd;
226 sd.AssociateDescriptor(pSecurityDescriptor);
227 sd.BeginSACLInteration();
228
229 if ((!sd.DescriptorContainsSACL())||(sd.HasNULLSACL()))
230 {
231 throw _T("Key has not SACL.\n");
232 }
233 if (!sd.HasValidSACL())
234 {
235 throw _T("Invalid SACL.\n");
236 }
237 DWORD nACECount = sd.GetSACLEntriesCount();
238 rConsole.Write(_T("SACL has "));
239 TCHAR Buffer[256];
240 rConsole.Write(_itot(nACECount,Buffer,10));
241 rConsole.Write(_T(" ACEs.\n"));
242 ASSERT(sizeof(ACL) == 8);
243 rConsole.Write(_T("\n"));
244 for (DWORD i = 0 ; i < nACECount ; i++)
245 {
246 rConsole.Write(_T("\n"));
247 rConsole.Write(_T("\tACE Index: "));
248 rConsole.Write(_itot(i,Buffer,10));
249 rConsole.Write(_T("\n"));
250 rConsole.Write(_T("\tAudit Type: "));
251 BOOL blnFailed, blnSuccessful;
252 if (sd.GetSACLEntry(i,blnFailed,blnSuccessful) != CSecurityDescriptor::SystemAudit)
253 {
254 rConsole.Write(_T("Unknown ACE type.\nCannot continue ACE list dump.\n"));
255 goto AbortDumpSACL;
256 }
257 if (blnFailed) rConsole.Write(_T("Failed access"));
258 if (blnFailed && blnSuccessful) rConsole.Write(_T(" & "));
259 if (blnSuccessful) rConsole.Write(_T("Successful access"));
260 rConsole.Write(_T("\n"));
261 PSID pSID = sd.GetCurrentACE_SID();
262 if ((pSID == NULL)||(!IsValidSid(pSID)))
263 {
264 rConsole.Write(_T("\tInvalid SID.\n"));
265 }
266 DWORD dwSIDStringSize = 0;
267 BOOL blnRet = GetTextualSid(pSID,NULL,&dwSIDStringSize);
268 ASSERT(!blnRet);
269 ASSERT(GetLastError() == ERROR_INSUFFICIENT_BUFFER);
270 TCHAR *pchSID = new TCHAR[dwSIDStringSize];
271 if(!GetTextualSid(pSID,pchSID,&dwSIDStringSize))
272 {
273 dwError = GetLastError();
274 ASSERT(dwError != ERROR_INSUFFICIENT_BUFFER);
275 rConsole.Write(_T("Error "));
276 TCHAR Buffer[256];
277 rConsole.Write(_itot(dwError,Buffer,10));
278 rConsole.Write(_T("\nGetting string representation of SID\n"));
279 }
280 else
281 {
282 rConsole.Write(_T("\tSID: "));
283 rConsole.Write(pchSID);
284 rConsole.Write(_T("\n"));
285 }
286 delete [] pchSID;
287 TCHAR *pchName, *pchDomainName;
288 DWORD dwNameBufferLength, dwDomainNameBufferLength;
289 dwNameBufferLength = 1024;
290 dwDomainNameBufferLength = 1024;
291 pchName = new TCHAR [dwNameBufferLength];
292 pchDomainName = new TCHAR [dwDomainNameBufferLength];
293 DWORD dwNameLength = dwNameBufferLength, dwDomainNameLength = dwDomainNameBufferLength;
294 SID_NAME_USE Use;
295 if (!LookupAccountSid(NULL,pSID,pchName,&dwNameLength,pchDomainName,&dwDomainNameLength,&Use))
296 {
297 rConsole.Write(_T("Error "));
298 TCHAR Buffer[256];
299 rConsole.Write(_itot(GetLastError(),Buffer,10));
300 rConsole.Write(_T("\n"));
301 }
302 else
303 {
304 rConsole.Write(_T("\tTrustee Domain: "));
305 rConsole.Write(pchDomainName);
306 rConsole.Write(_T("\n"));
307 rConsole.Write(_T("\tTrustee Name: "));
308 rConsole.Write(pchName);
309 rConsole.Write(_T("\n\tSID type: "));
310 rConsole.Write(GetSidTypeName(Use));
311 rConsole.Write(_T("\n"));
312 }
313 DWORD dwAccessMask;
314 sd.GetCurrentACE_AccessMask(dwAccessMask);
315 wsprintf(Buffer,_T("\tAccess Mask: 0x%08lX\n"),dwAccessMask);
316 rConsole.Write(Buffer);
317 if (dwAccessMask & GENERIC_READ)
318 {
319 rConsole.Write(_T("\t\tGENERIC_READ\n"));
320 }
321 if (dwAccessMask & GENERIC_WRITE)
322 {
323 rConsole.Write(_T("\t\tGENERIC_WRITE\n"));
324 }
325 if (dwAccessMask & GENERIC_EXECUTE)
326 {
327 rConsole.Write(_T("\t\tGENERIC_EXECUTE\n"));
328 }
329 if (dwAccessMask & GENERIC_ALL)
330 {
331 rConsole.Write(_T("\t\tGENERIC_ALL\n"));
332 }
333 if (dwAccessMask & SYNCHRONIZE)
334 {
335 rConsole.Write(_T("\t\tSYNCHRONIZE\n"));
336 }
337 if (dwAccessMask & WRITE_OWNER)
338 {
339 rConsole.Write(_T("\t\tWRITE_OWNER\n"));
340 }
341 if (dwAccessMask & WRITE_DAC)
342 {
343 rConsole.Write(_T("\t\tWRITE_DAC\n"));
344 }
345 if (dwAccessMask & READ_CONTROL)
346 {
347 rConsole.Write(_T("\t\tREAD_CONTROL\n"));
348 }
349 if (dwAccessMask & DELETE)
350 {
351 rConsole.Write(_T("\t\tDELETE\n"));
352 }
353 if (dwAccessMask & KEY_CREATE_LINK)
354 {
355 rConsole.Write(_T("\t\tKEY_CREATE_LINK\n"));
356 }
357 if (dwAccessMask & KEY_NOTIFY)
358 {
359 rConsole.Write(_T("\t\tKEY_NOTIFY\n"));
360 }
361 if (dwAccessMask & KEY_ENUMERATE_SUB_KEYS)
362 {
363 rConsole.Write(_T("\t\tKEY_ENUMERATE_SUB_KEYS\n"));
364 }
365 if (dwAccessMask & KEY_CREATE_SUB_KEY)
366 {
367 rConsole.Write(_T("\t\tKEY_CREATE_SUB_KEY\n"));
368 }
369 if (dwAccessMask & KEY_SET_VALUE)
370 {
371 rConsole.Write(_T("\t\tKEY_SET_VALUE\n"));
372 }
373 if (dwAccessMask & KEY_QUERY_VALUE)
374 {
375 rConsole.Write(_T("\t\tKEY_QUERY_VALUE\n"));
376 }
377 } // for
378 AbortDumpSACL:
379 delete pSecurityDescriptor;
380 }
381 catch(TCHAR *pchError)
382 {
383 rConsole.Write(pchError);
384 }
385 } // if (blnDo)
386
387 return 0;
388 }
389
390 const TCHAR * CShellCommandSACL::GetHelpString()
391 {
392 return SACL_CMD_SHORT_DESC
393 _T("Syntax: ") SACL_CMD _T(" [<KEY>] [/?]\n\n")
394 _T(" <KEY> - Optional relative path of desired key.\n")
395 _T(" /? - This help.\n\n")
396 _T("Without parameters, command displays SACL of current key.\n");
397 }
398
399 const TCHAR * CShellCommandSACL::GetHelpShortDescriptionString()
400 {
401 return SACL_CMD_SHORT_DESC;
402 }