2 * regexpl - Console Registry Explorer
4 * Copyright (C) 2000-2005 Nedko Arnaudov <nedko@users.sourceforge.net>
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.
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.
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.
22 // ShellCommandSACL.cpp: implementation of the CShellCommandSACL class.
24 //////////////////////////////////////////////////////////////////////
27 #include "ShellCommandSACL.h"
28 #include "RegistryExplorer.h"
29 #include "SecurityDescriptor.h"
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")
35 //////////////////////////////////////////////////////////////////////
36 // Construction/Destruction
37 //////////////////////////////////////////////////////////////////////
39 CShellCommandSACL::CShellCommandSACL(CRegistryTree
& rTree
):m_rTree(rTree
)
44 CShellCommandSACL::~CShellCommandSACL()
49 BOOL
CShellCommandSACL::Match(const TCHAR
*pchCommand
)
51 if (_tcsicmp(pchCommand
,SACL_CMD
) == 0)
53 if (_tcsnicmp(pchCommand
,SACL_CMD
_T(".."),SACL_CMD_LENGTH
+2*sizeof(TCHAR
)) == 0)
55 if (_tcsnicmp(pchCommand
,SACL_CMD
_T("/") ,SACL_CMD_LENGTH
+1*sizeof(TCHAR
)) == 0)
57 if (_tcsnicmp(pchCommand
,SACL_CMD
_T("\\"),SACL_CMD_LENGTH
+1*sizeof(TCHAR
)) == 0)
62 int CShellCommandSACL::Execute(CConsole
&rConsole
, CArgumentParser
& rArguments
)
64 #define ERROR_MSG_BUFFER_SIZE 1024
65 TCHAR pszError_msg
[ERROR_MSG_BUFFER_SIZE
];
66 pszError_msg
[ERROR_MSG_BUFFER_SIZE
-1] = 0;
68 rArguments
.ResetArgumentIteration();
70 const TCHAR
*pszKey
= NULL
;
72 BOOL blnBadParameter
= FALSE
;
74 const TCHAR
*pszParameter
;
75 const TCHAR
*pszCommandItself
= rArguments
.GetNextArgument();
77 PISECURITY_DESCRIPTOR pSecurityDescriptor
= NULL
;
78 CSecurityDescriptor sd
;
79 HANDLE hThreadToken
= INVALID_HANDLE_VALUE
;
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))
84 pszKey
= pszCommandItself
+ SACL_CMD_LENGTH
;
86 else if (_tcsnicmp(pszCommandItself
,SACL_CMD
_T("/"),SACL_CMD_LENGTH
+1*sizeof(TCHAR
)) == 0)
88 pszParameter
= pszCommandItself
+ SACL_CMD_LENGTH
;
89 goto CheckSACLArgument
;
92 while((pszParameter
= rArguments
.GetNextArgument()) != NULL
)
95 blnBadParameter
= FALSE
;
96 if ((_tcsicmp(pszParameter
,_T("/?")) == 0)||
97 (_tcsicmp(pszParameter
,_T("-?")) == 0))
100 blnDo
= pszKey
!= NULL
;
104 pszKey
= pszParameter
;
109 blnBadParameter
= TRUE
;
113 rConsole
.Write(_T("Bad parameter: "));
114 rConsole
.Write(pszParameter
);
115 rConsole
.Write(_T("\n"));
121 ASSERT(hThreadToken
== INVALID_HANDLE_VALUE
);
124 if (!OpenThreadToken(GetCurrentThread(),TOKEN_ADJUST_PRIVILEGES
|TOKEN_QUERY
,FALSE
,&hThreadToken
))
125 { // OpenThreadToken failed
126 dwError
= GetLastError();
127 if (dwError
!= ERROR_NO_TOKEN
)
129 _sntprintf(pszError_msg
,ERROR_MSG_BUFFER_SIZE
-1,_T("\nCannot open thread token.\nOpenThreadToken fails with error: %u\n"),(unsigned int)dwError
);
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
))
137 _sntprintf(pszError_msg
,ERROR_MSG_BUFFER_SIZE
-1,_T("\nCannot open process token.\nOpenProcessToken fails with error: %u\n"),(unsigned int)GetLastError());
142 ASSERT(hThreadToken
!= INVALID_HANDLE_VALUE
);
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
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());
158 blnAdjRet
= AdjustTokenPrivileges(
162 sizeof(TOKEN_PRIVILEGES
),
163 (PTOKEN_PRIVILEGES
)NULL
,
165 dwError
= GetLastError();
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(""));
172 if (dwError
!= ERROR_SUCCESS
)
174 if (dwError
== ERROR_NOT_ALL_ASSIGNED
)
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
);
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
);
186 if (!m_rTree
.GetKey(pszKey
?pszKey
:_T("."),KEY_QUERY_VALUE
|READ_CONTROL
|ACCESS_SYSTEM_SECURITY
,Key
))
188 rConsole
.Write(m_rTree
.GetLastErrorDescription());
194 rConsole
.Write(GetHelpString());
198 rConsole
.Write(_T("\n"));
205 _tcsncpy(pszError_msg
,SACL_CMD COMMAND_NA_ON_ROOT
,ERROR_MSG_BUFFER_SIZE
-1);
209 DWORD dwSecurityDescriptorLength
;
210 rConsole
.Write(_T("Key : "));
211 rConsole
.Write(_T("\\"));
213 rConsole
.Write(Key
.GetKeyName());
214 rConsole
.Write(_T("\n"));
215 dwError
= Key
.GetSecurityDescriptorLength(&dwSecurityDescriptorLength
);
216 if (dwError
!= ERROR_SUCCESS
)
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
);
222 pSecurityDescriptor
= (PISECURITY_DESCRIPTOR
) new (std::nothrow
) unsigned char [dwSecurityDescriptorLength
];
223 if (!pSecurityDescriptor
)
225 _tcsncpy(pszError_msg
,_T("\nOut of memory.\n"),ERROR_MSG_BUFFER_SIZE
-1);
229 DWORD dwSecurityDescriptorLength1
;
230 dwSecurityDescriptorLength1
= dwSecurityDescriptorLength
;
231 dwError
= Key
.GetSecurityDescriptor((SECURITY_INFORMATION
)SACL_SECURITY_INFORMATION
,pSecurityDescriptor
,&dwSecurityDescriptorLength1
);
232 if (dwError
!= ERROR_SUCCESS
)
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(""));
238 sd
.AssociateDescriptor(pSecurityDescriptor
);
239 sd
.BeginSACLInteration();
241 if ((!sd
.DescriptorContainsSACL())||(sd
.HasNULLSACL()))
243 _tcsncpy(pszError_msg
,_T("Key has not SACL.\n"),ERROR_MSG_BUFFER_SIZE
-1);
247 if (!sd
.HasValidSACL())
249 _tcsncpy(pszError_msg
,_T("Invalid SACL.\n"),ERROR_MSG_BUFFER_SIZE
-1);
254 nACECount
= sd
.GetSACLEntriesCount();
255 rConsole
.Write(_T("SACL has "));
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
++)
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
)
271 rConsole
.Write(_T("Unknown ACE type.\nCannot continue ACE list dump.\n"));
276 rConsole
.Write(_T("Failed access"));
278 if (blnFailed
&& blnSuccessful
)
279 rConsole
.Write(_T(" & "));
281 rConsole
.Write(_T("Successful access"));
282 rConsole
.Write(_T("\n"));
284 PSID pSID
= sd
.GetCurrentACE_SID();
285 if ((pSID
== NULL
)||(!IsValidSid(pSID
)))
287 rConsole
.Write(_T("\tInvalid SID.\n"));
290 DWORD dwSIDStringSize
= 0;
291 BOOL blnRet
= GetTextualSid(pSID
,NULL
,&dwSIDStringSize
);
293 ASSERT(GetLastError() == ERROR_INSUFFICIENT_BUFFER
);
294 TCHAR
*pszSID
= new (std::nothrow
) TCHAR
[dwSIDStringSize
];
298 _tcsncpy(pszError_msg
,_T("\nOut of memory.\n"),ERROR_MSG_BUFFER_SIZE
-1);
302 if(!GetTextualSid(pSID
,pszSID
,&dwSIDStringSize
))
304 dwError
= GetLastError();
305 ASSERT(dwError
!= ERROR_INSUFFICIENT_BUFFER
);
306 rConsole
.Write(_T("Error "));
308 rConsole
.Write(_itoa(dwError
,Buffer
,10));
309 rConsole
.Write(_T("\nGetting string representation of SID\n"));
313 rConsole
.Write(_T("\tSID: "));
314 rConsole
.Write(pszSID
);
315 rConsole
.Write(_T("\n"));
319 TCHAR
*pszName
, *pszDomainName
;
320 DWORD dwNameBufferLength
, dwDomainNameBufferLength
;
321 dwNameBufferLength
= 1024;
322 dwDomainNameBufferLength
= 1024;
324 pszName
= new (std::nothrow
) TCHAR
[dwNameBufferLength
];
327 _tcsncpy(pszError_msg
,_T("\nOut of memory.\n"),ERROR_MSG_BUFFER_SIZE
-1);
331 pszDomainName
= new (std::nothrow
) TCHAR
[dwDomainNameBufferLength
];
334 _tcsncpy(pszError_msg
,_T("\nOut of memory.\n"),ERROR_MSG_BUFFER_SIZE
-1);
339 DWORD dwNameLength
= dwNameBufferLength
, dwDomainNameLength
= dwDomainNameBufferLength
;
341 if (!LookupAccountSid(NULL
,pSID
,pszName
,&dwNameLength
,pszDomainName
,&dwDomainNameLength
,&Use
))
343 rConsole
.Write(_T("Error "));
345 rConsole
.Write(_itoa(GetLastError(),Buffer
,10));
346 rConsole
.Write(_T("\n"));
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"));
360 sd
.GetCurrentACE_AccessMask(dwAccessMask
);
361 wsprintf(Buffer
,_T("\tAccess Mask: 0x%08lX\n"),dwAccessMask
);
362 rConsole
.Write(Buffer
);
363 if (dwAccessMask
& GENERIC_READ
)
365 rConsole
.Write(_T("\t\tGENERIC_READ\n"));
367 if (dwAccessMask
& GENERIC_WRITE
)
369 rConsole
.Write(_T("\t\tGENERIC_WRITE\n"));
371 if (dwAccessMask
& GENERIC_EXECUTE
)
373 rConsole
.Write(_T("\t\tGENERIC_EXECUTE\n"));
375 if (dwAccessMask
& GENERIC_ALL
)
377 rConsole
.Write(_T("\t\tGENERIC_ALL\n"));
379 if (dwAccessMask
& SYNCHRONIZE
)
381 rConsole
.Write(_T("\t\tSYNCHRONIZE\n"));
383 if (dwAccessMask
& WRITE_OWNER
)
385 rConsole
.Write(_T("\t\tWRITE_OWNER\n"));
387 if (dwAccessMask
& WRITE_DAC
)
389 rConsole
.Write(_T("\t\tWRITE_DAC\n"));
391 if (dwAccessMask
& READ_CONTROL
)
393 rConsole
.Write(_T("\t\tREAD_CONTROL\n"));
395 if (dwAccessMask
& DELETE
)
397 rConsole
.Write(_T("\t\tDELETE\n"));
399 if (dwAccessMask
& KEY_CREATE_LINK
)
401 rConsole
.Write(_T("\t\tKEY_CREATE_LINK\n"));
403 if (dwAccessMask
& KEY_NOTIFY
)
405 rConsole
.Write(_T("\t\tKEY_NOTIFY\n"));
407 if (dwAccessMask
& KEY_ENUMERATE_SUB_KEYS
)
409 rConsole
.Write(_T("\t\tKEY_ENUMERATE_SUB_KEYS\n"));
411 if (dwAccessMask
& KEY_CREATE_SUB_KEY
)
413 rConsole
.Write(_T("\t\tKEY_CREATE_SUB_KEY\n"));
415 if (dwAccessMask
& KEY_SET_VALUE
)
417 rConsole
.Write(_T("\t\tKEY_SET_VALUE\n"));
419 if (dwAccessMask
& KEY_QUERY_VALUE
)
421 rConsole
.Write(_T("\t\tKEY_QUERY_VALUE\n"));
425 delete[] pszDomainName
;
429 ASSERT(pSecurityDescriptor
);
430 delete pSecurityDescriptor
;
432 VERIFY(CloseHandle(hThreadToken
));
436 if (pSecurityDescriptor
)
437 delete pSecurityDescriptor
;
439 if (hThreadToken
!= INVALID_HANDLE_VALUE
)
440 VERIFY(CloseHandle(hThreadToken
));
442 rConsole
.Write(pszError_msg
);
446 const TCHAR
* CShellCommandSACL::GetHelpString()
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");
455 const TCHAR
* CShellCommandSACL::GetHelpShortDescriptionString()
457 return SACL_CMD_SHORT_DESC
;