0ff8c693187561d813ab4adff8715d05382df6eb
[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 (std::nothrow) 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 (std::nothrow) 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 (std::nothrow) 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 (std::nothrow) TCHAR [dwDomainNameBufferLength];
333 if (!pszDomainName)
334 {
335 _tcsncpy(pszError_msg,_T("\nOut of memory.\n"),ERROR_MSG_BUFFER_SIZE-1);
336 delete[] pszName;
337 goto Error;
338 }
339
340 DWORD dwNameLength = dwNameBufferLength, dwDomainNameLength = dwDomainNameBufferLength;
341 SID_NAME_USE Use;
342 if (!LookupAccountSid(NULL,pSID,pszName,&dwNameLength,pszDomainName,&dwDomainNameLength,&Use))
343 {
344 rConsole.Write(_T("Error "));
345 TCHAR Buffer[256];
346 rConsole.Write(_itoa(GetLastError(),Buffer,10));
347 rConsole.Write(_T("\n"));
348 }
349 else
350 {
351 rConsole.Write(_T("\tTrustee Domain: "));
352 rConsole.Write(pszDomainName);
353 rConsole.Write(_T("\n"));
354 rConsole.Write(_T("\tTrustee Name: "));
355 rConsole.Write(pszName);
356 rConsole.Write(_T("\n\tSID type: "));
357 rConsole.Write(GetSidTypeName(Use));
358 rConsole.Write(_T("\n"));
359 }
360 DWORD dwAccessMask;
361 sd.GetCurrentACE_AccessMask(dwAccessMask);
362 wsprintf(Buffer,_T("\tAccess Mask: 0x%08lX\n"),dwAccessMask);
363 rConsole.Write(Buffer);
364 if (dwAccessMask & GENERIC_READ)
365 {
366 rConsole.Write(_T("\t\tGENERIC_READ\n"));
367 }
368 if (dwAccessMask & GENERIC_WRITE)
369 {
370 rConsole.Write(_T("\t\tGENERIC_WRITE\n"));
371 }
372 if (dwAccessMask & GENERIC_EXECUTE)
373 {
374 rConsole.Write(_T("\t\tGENERIC_EXECUTE\n"));
375 }
376 if (dwAccessMask & GENERIC_ALL)
377 {
378 rConsole.Write(_T("\t\tGENERIC_ALL\n"));
379 }
380 if (dwAccessMask & SYNCHRONIZE)
381 {
382 rConsole.Write(_T("\t\tSYNCHRONIZE\n"));
383 }
384 if (dwAccessMask & WRITE_OWNER)
385 {
386 rConsole.Write(_T("\t\tWRITE_OWNER\n"));
387 }
388 if (dwAccessMask & WRITE_DAC)
389 {
390 rConsole.Write(_T("\t\tWRITE_DAC\n"));
391 }
392 if (dwAccessMask & READ_CONTROL)
393 {
394 rConsole.Write(_T("\t\tREAD_CONTROL\n"));
395 }
396 if (dwAccessMask & DELETE)
397 {
398 rConsole.Write(_T("\t\tDELETE\n"));
399 }
400 if (dwAccessMask & KEY_CREATE_LINK)
401 {
402 rConsole.Write(_T("\t\tKEY_CREATE_LINK\n"));
403 }
404 if (dwAccessMask & KEY_NOTIFY)
405 {
406 rConsole.Write(_T("\t\tKEY_NOTIFY\n"));
407 }
408 if (dwAccessMask & KEY_ENUMERATE_SUB_KEYS)
409 {
410 rConsole.Write(_T("\t\tKEY_ENUMERATE_SUB_KEYS\n"));
411 }
412 if (dwAccessMask & KEY_CREATE_SUB_KEY)
413 {
414 rConsole.Write(_T("\t\tKEY_CREATE_SUB_KEY\n"));
415 }
416 if (dwAccessMask & KEY_SET_VALUE)
417 {
418 rConsole.Write(_T("\t\tKEY_SET_VALUE\n"));
419 }
420 if (dwAccessMask & KEY_QUERY_VALUE)
421 {
422 rConsole.Write(_T("\t\tKEY_QUERY_VALUE\n"));
423 }
424
425 delete[] pszName;
426 delete[] pszDomainName;
427 } // for
428
429 AbortDumpSACL:
430 ASSERT(pSecurityDescriptor);
431 delete pSecurityDescriptor;
432
433 VERIFY(CloseHandle(hThreadToken));
434
435 return 0;
436 Error:
437 if (pSecurityDescriptor)
438 delete pSecurityDescriptor;
439
440 if (hThreadToken != INVALID_HANDLE_VALUE)
441 VERIFY(CloseHandle(hThreadToken));
442
443 rConsole.Write(pszError_msg);
444 return 0;
445 }
446
447 const TCHAR * CShellCommandSACL::GetHelpString()
448 {
449 return SACL_CMD_SHORT_DESC
450 _T("Syntax: ") SACL_CMD _T(" [<KEY>] [/?]\n\n")
451 _T(" <KEY> - Optional relative path of desired key.\n")
452 _T(" /? - This help.\n\n")
453 _T("Without parameters, command displays SACL of current key.\n");
454 }
455
456 const TCHAR * CShellCommandSACL::GetHelpShortDescriptionString()
457 {
458 return SACL_CMD_SHORT_DESC;
459 }