[FONTSUB] Fix buildĀ²
[reactos.git] / modules / rosapps / applications / sysutils / regexpl / ShellCommandSACL.cpp
1 /*
2 * regexpl - Console Registry Explorer
3 *
4 * Copyright (C) 2000-2005 Nedko Arnaudov <nedko@users.sourceforge.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program 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
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; see the file COPYING. If not, write to
18 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 */
21
22 // ShellCommandSACL.cpp: implementation of the CShellCommandSACL class.
23 //
24 //////////////////////////////////////////////////////////////////////
25
26 #include "ph.h"
27 #include "ShellCommandSACL.h"
28 #include "RegistryExplorer.h"
29 #include "SecurityDescriptor.h"
30
31 #define SACL_CMD _T("SACL")
32 #define SACL_CMD_LENGTH COMMAND_LENGTH(SACL_CMD)
33 #define SACL_CMD_SHORT_DESC SACL_CMD _T(" command is used to view")/*"/edit"*/_T(" key's SACL.\n")
34
35 //////////////////////////////////////////////////////////////////////
36 // Construction/Destruction
37 //////////////////////////////////////////////////////////////////////
38
39 CShellCommandSACL::CShellCommandSACL(CRegistryTree& rTree):m_rTree(rTree)
40 {
41
42 }
43
44 CShellCommandSACL::~CShellCommandSACL()
45 {
46
47 }
48
49 BOOL CShellCommandSACL::Match(const TCHAR *pchCommand)
50 {
51 if (_tcsicmp(pchCommand,SACL_CMD) == 0)
52 return TRUE;
53 if (_tcsnicmp(pchCommand,SACL_CMD _T(".."),SACL_CMD_LENGTH+2*sizeof(TCHAR)) == 0)
54 return TRUE;
55 if (_tcsnicmp(pchCommand,SACL_CMD _T("/") ,SACL_CMD_LENGTH+1*sizeof(TCHAR)) == 0)
56 return TRUE;
57 if (_tcsnicmp(pchCommand,SACL_CMD _T("\\"),SACL_CMD_LENGTH+1*sizeof(TCHAR)) == 0)
58 return TRUE;
59 return FALSE;
60 }
61
62 int CShellCommandSACL::Execute(CConsole &rConsole, CArgumentParser& rArguments)
63 {
64 #define ERROR_MSG_BUFFER_SIZE 1024
65 TCHAR pszError_msg[ERROR_MSG_BUFFER_SIZE];
66 pszError_msg[ERROR_MSG_BUFFER_SIZE-1] = 0;
67
68 rArguments.ResetArgumentIteration();
69
70 const TCHAR *pszKey = NULL;
71 BOOL blnDo = TRUE;
72 BOOL blnBadParameter = FALSE;
73 BOOL blnHelp = FALSE;
74 const TCHAR *pszParameter;
75 const TCHAR *pszCommandItself = rArguments.GetNextArgument();
76 DWORD dwError;
77 PISECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
78 CSecurityDescriptor sd;
79 HANDLE hThreadToken = INVALID_HANDLE_VALUE;
80
81 if ((_tcsnicmp(pszCommandItself,SACL_CMD _T(".."),SACL_CMD_LENGTH+2*sizeof(TCHAR)) == 0)||
82 (_tcsnicmp(pszCommandItself,SACL_CMD _T("\\"),SACL_CMD_LENGTH+1*sizeof(TCHAR)) == 0))
83 {
84 pszKey = pszCommandItself + SACL_CMD_LENGTH;
85 }
86 else if (_tcsnicmp(pszCommandItself,SACL_CMD _T("/"),SACL_CMD_LENGTH+1*sizeof(TCHAR)) == 0)
87 {
88 pszParameter = pszCommandItself + SACL_CMD_LENGTH;
89 goto CheckSACLArgument;
90 }
91
92 while((pszParameter = rArguments.GetNextArgument()) != NULL)
93 {
94 CheckSACLArgument:
95 blnBadParameter = FALSE;
96 if ((_tcsicmp(pszParameter,_T("/?")) == 0)||
97 (_tcsicmp(pszParameter,_T("-?")) == 0))
98 {
99 blnHelp = TRUE;
100 blnDo = pszKey != NULL;
101 }
102 else if (!pszKey)
103 {
104 pszKey = pszParameter;
105 blnDo = TRUE;
106 }
107 else
108 {
109 blnBadParameter = TRUE;
110 }
111 if (blnBadParameter)
112 {
113 rConsole.Write(_T("Bad parameter: "));
114 rConsole.Write(pszParameter);
115 rConsole.Write(_T("\n"));
116 }
117 }
118
119 CRegistryKey Key;
120
121 ASSERT(hThreadToken == INVALID_HANDLE_VALUE);
122
123 // Open thread token
124 if (!OpenThreadToken(GetCurrentThread(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,FALSE,&hThreadToken))
125 { // OpenThreadToken failed
126 dwError = GetLastError();
127 if (dwError != ERROR_NO_TOKEN)
128 {
129 _sntprintf(pszError_msg,ERROR_MSG_BUFFER_SIZE-1,_T("\nCannot open thread token.\nOpenThreadToken fails with error: %u\n"),(unsigned int)dwError);
130 goto Error;
131 }
132
133 // If the thread does not have an access token, we'll examine the
134 // access token associated with the process.
135 if (!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hThreadToken))
136 {
137 _sntprintf(pszError_msg,ERROR_MSG_BUFFER_SIZE-1,_T("\nCannot open process token.\nOpenProcessToken fails with error: %u\n"),(unsigned int)GetLastError());
138 goto Error;
139 }
140 }
141
142 ASSERT(hThreadToken != INVALID_HANDLE_VALUE);
143
144 // enable SeSecurityPrivilege privilege
145 TOKEN_PRIVILEGES priv;
146 priv.PrivilegeCount = 1;
147 priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
148 if (!LookupPrivilegeValue(
149 NULL, // lookup privilege on local system
150 SE_SECURITY_NAME, // privilege to lookup
151 &(priv.Privileges[0].Luid))) // receives LUID of privilege
152 {
153 _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());
154 goto Error;
155 }
156
157 BOOL blnAdjRet;
158 blnAdjRet = AdjustTokenPrivileges(
159 hThreadToken,
160 FALSE,
161 &priv,
162 sizeof(TOKEN_PRIVILEGES),
163 (PTOKEN_PRIVILEGES)NULL,
164 (PDWORD)NULL);
165 dwError = GetLastError();
166 if (!blnAdjRet)
167 {
168 _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(""));
169 goto Error;
170 }
171
172 if (dwError != ERROR_SUCCESS)
173 {
174 if (dwError == ERROR_NOT_ALL_ASSIGNED)
175 {
176 _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);
177 }
178 else
179 {
180 _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);
181 }
182
183 goto Error;
184 }
185
186 if (!m_rTree.GetKey(pszKey?pszKey:_T("."),KEY_QUERY_VALUE|READ_CONTROL|ACCESS_SYSTEM_SECURITY,Key))
187 {
188 rConsole.Write(m_rTree.GetLastErrorDescription());
189 blnDo = FALSE;
190 }
191
192 if (blnHelp)
193 {
194 rConsole.Write(GetHelpString());
195 }
196
197 if (blnDo&&blnHelp)
198 rConsole.Write(_T("\n"));
199
200 if (!blnDo)
201 return 0;
202
203 if (Key.IsRoot())
204 {
205 _tcsncpy(pszError_msg,SACL_CMD COMMAND_NA_ON_ROOT,ERROR_MSG_BUFFER_SIZE-1);
206 goto Error;
207 }
208
209 DWORD dwSecurityDescriptorLength;
210 rConsole.Write(_T("Key : "));
211 rConsole.Write(_T("\\"));
212
213 rConsole.Write(Key.GetKeyName());
214 rConsole.Write(_T("\n"));
215 dwError = Key.GetSecurityDescriptorLength(&dwSecurityDescriptorLength);
216 if (dwError != ERROR_SUCCESS)
217 {
218 _sntprintf(pszError_msg,ERROR_MSG_BUFFER_SIZE-1,_T("\nCannot get security descriptor's length for current key.\nError: %u\n"),(unsigned int)dwError);
219 goto Error;
220 }
221
222 pSecurityDescriptor = (PISECURITY_DESCRIPTOR) new (std::nothrow) unsigned char [dwSecurityDescriptorLength];
223 if (!pSecurityDescriptor)
224 {
225 _tcsncpy(pszError_msg,_T("\nOut of memory.\n"),ERROR_MSG_BUFFER_SIZE-1);
226 goto Error;
227 }
228
229 DWORD dwSecurityDescriptorLength1;
230 dwSecurityDescriptorLength1 = dwSecurityDescriptorLength;
231 dwError = Key.GetSecurityDescriptor((SECURITY_INFORMATION)SACL_SECURITY_INFORMATION,pSecurityDescriptor,&dwSecurityDescriptorLength1);
232 if (dwError != ERROR_SUCCESS)
233 {
234 _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(""));
235 goto Error;
236 }
237
238 sd.AssociateDescriptor(pSecurityDescriptor);
239 sd.BeginSACLInteration();
240
241 if ((!sd.DescriptorContainsSACL())||(sd.HasNULLSACL()))
242 {
243 _tcsncpy(pszError_msg,_T("Key has not SACL.\n"),ERROR_MSG_BUFFER_SIZE-1);
244 goto Error;
245 }
246
247 if (!sd.HasValidSACL())
248 {
249 _tcsncpy(pszError_msg,_T("Invalid SACL.\n"),ERROR_MSG_BUFFER_SIZE-1);
250 goto Error;
251 }
252
253 DWORD nACECount;
254 nACECount = sd.GetSACLEntriesCount();
255 rConsole.Write(_T("SACL has "));
256 TCHAR Buffer[256];
257 rConsole.Write(_itoa(nACECount,Buffer,10));
258 rConsole.Write(_T(" ACEs.\n"));
259 ASSERT(sizeof(ACL) == 8);
260 rConsole.Write(_T("\n"));
261 for (DWORD i = 0 ; i < nACECount ; i++)
262 {
263 rConsole.Write(_T("\n"));
264 rConsole.Write(_T("\tACE Index: "));
265 rConsole.Write(_itoa(i,Buffer,10));
266 rConsole.Write(_T("\n"));
267 rConsole.Write(_T("\tAudit Type: "));
268 BOOL blnFailed, blnSuccessful;
269 if (sd.GetSACLEntry(i,blnFailed,blnSuccessful) != CSecurityDescriptor::SystemAudit)
270 {
271 rConsole.Write(_T("Unknown ACE type.\nCannot continue ACE list dump.\n"));
272 goto AbortDumpSACL;
273 }
274
275 if (blnFailed)
276 rConsole.Write(_T("Failed access"));
277
278 if (blnFailed && blnSuccessful)
279 rConsole.Write(_T(" & "));
280 if (blnSuccessful)
281 rConsole.Write(_T("Successful access"));
282 rConsole.Write(_T("\n"));
283
284 PSID pSID = sd.GetCurrentACE_SID();
285 if ((pSID == NULL)||(!IsValidSid(pSID)))
286 {
287 rConsole.Write(_T("\tInvalid SID.\n"));
288 }
289
290 DWORD dwSIDStringSize = 0;
291 BOOL blnRet = GetTextualSid(pSID,NULL,&dwSIDStringSize);
292 ASSERT(!blnRet);
293 ASSERT(GetLastError() == ERROR_INSUFFICIENT_BUFFER);
294 TCHAR *pszSID = new (std::nothrow) TCHAR[dwSIDStringSize];
295
296 if (!pszSID)
297 {
298 _tcsncpy(pszError_msg,_T("\nOut of memory.\n"),ERROR_MSG_BUFFER_SIZE-1);
299 goto Error;
300 }
301
302 if(!GetTextualSid(pSID,pszSID,&dwSIDStringSize))
303 {
304 dwError = GetLastError();
305 ASSERT(dwError != ERROR_INSUFFICIENT_BUFFER);
306 rConsole.Write(_T("Error "));
307 TCHAR Buffer[256];
308 rConsole.Write(_itoa(dwError,Buffer,10));
309 rConsole.Write(_T("\nGetting string representation of SID\n"));
310 }
311 else
312 {
313 rConsole.Write(_T("\tSID: "));
314 rConsole.Write(pszSID);
315 rConsole.Write(_T("\n"));
316 }
317 delete[] pszSID;
318
319 TCHAR *pszName, *pszDomainName;
320 DWORD dwNameBufferLength, dwDomainNameBufferLength;
321 dwNameBufferLength = 1024;
322 dwDomainNameBufferLength = 1024;
323
324 pszName = new (std::nothrow) TCHAR [dwNameBufferLength];
325 if (!pszName)
326 {
327 _tcsncpy(pszError_msg,_T("\nOut of memory.\n"),ERROR_MSG_BUFFER_SIZE-1);
328 goto Error;
329 }
330
331 pszDomainName = new (std::nothrow) TCHAR [dwDomainNameBufferLength];
332 if (!pszDomainName)
333 {
334 _tcsncpy(pszError_msg,_T("\nOut of memory.\n"),ERROR_MSG_BUFFER_SIZE-1);
335 delete[] pszName;
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
424 delete[] pszName;
425 delete[] pszDomainName;
426 } // for
427
428 AbortDumpSACL:
429 ASSERT(pSecurityDescriptor);
430 delete pSecurityDescriptor;
431
432 VERIFY(CloseHandle(hThreadToken));
433
434 return 0;
435 Error:
436 if (pSecurityDescriptor)
437 delete pSecurityDescriptor;
438
439 if (hThreadToken != INVALID_HANDLE_VALUE)
440 VERIFY(CloseHandle(hThreadToken));
441
442 rConsole.Write(pszError_msg);
443 return 0;
444 }
445
446 const TCHAR * CShellCommandSACL::GetHelpString()
447 {
448 return SACL_CMD_SHORT_DESC
449 _T("Syntax: ") SACL_CMD _T(" [<KEY>] [/?]\n\n")
450 _T(" <KEY> - Optional relative path of desired key.\n")
451 _T(" /? - This help.\n\n")
452 _T("Without parameters, command displays SACL of current key.\n");
453 }
454
455 const TCHAR * CShellCommandSACL::GetHelpShortDescriptionString()
456 {
457 return SACL_CMD_SHORT_DESC;
458 }