3 * regexpl - Console Registry Explorer
5 * Copyright (C) 2000-2005 Nedko Arnaudov <nedko@users.sourceforge.net>
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.
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.
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.
23 // ShellCommandSACL.cpp: implementation of the CShellCommandSACL class.
25 //////////////////////////////////////////////////////////////////////
28 #include "ShellCommandSACL.h"
29 #include "RegistryExplorer.h"
30 #include "SecurityDescriptor.h"
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")
36 //////////////////////////////////////////////////////////////////////
37 // Construction/Destruction
38 //////////////////////////////////////////////////////////////////////
40 CShellCommandSACL::CShellCommandSACL(CRegistryTree
& rTree
):m_rTree(rTree
)
45 CShellCommandSACL::~CShellCommandSACL()
50 BOOL
CShellCommandSACL::Match(const TCHAR
*pchCommand
)
52 if (_tcsicmp(pchCommand
,SACL_CMD
) == 0)
54 if (_tcsnicmp(pchCommand
,SACL_CMD
_T(".."),SACL_CMD_LENGTH
+2*sizeof(TCHAR
)) == 0)
56 if (_tcsnicmp(pchCommand
,SACL_CMD
_T("/") ,SACL_CMD_LENGTH
+1*sizeof(TCHAR
)) == 0)
58 if (_tcsnicmp(pchCommand
,SACL_CMD
_T("\\"),SACL_CMD_LENGTH
+1*sizeof(TCHAR
)) == 0)
63 int CShellCommandSACL::Execute(CConsole
&rConsole
, CArgumentParser
& rArguments
)
65 #define ERROR_MSG_BUFFER_SIZE 1024
66 TCHAR pszError_msg
[ERROR_MSG_BUFFER_SIZE
];
67 pszError_msg
[ERROR_MSG_BUFFER_SIZE
-1] = 0;
69 rArguments
.ResetArgumentIteration();
71 const TCHAR
*pszKey
= NULL
;
73 BOOL blnBadParameter
= FALSE
;
75 const TCHAR
*pszParameter
;
76 const TCHAR
*pszCommandItself
= rArguments
.GetNextArgument();
78 PISECURITY_DESCRIPTOR pSecurityDescriptor
= NULL
;
79 CSecurityDescriptor sd
;
80 HANDLE hThreadToken
= INVALID_HANDLE_VALUE
;
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))
85 pszKey
= pszCommandItself
+ SACL_CMD_LENGTH
;
87 else if (_tcsnicmp(pszCommandItself
,SACL_CMD
_T("/"),SACL_CMD_LENGTH
+1*sizeof(TCHAR
)) == 0)
89 pszParameter
= pszCommandItself
+ SACL_CMD_LENGTH
;
90 goto CheckSACLArgument
;
93 while((pszParameter
= rArguments
.GetNextArgument()) != NULL
)
96 blnBadParameter
= FALSE
;
97 if ((_tcsicmp(pszParameter
,_T("/?")) == 0)||
98 (_tcsicmp(pszParameter
,_T("-?")) == 0))
101 blnDo
= pszKey
!= NULL
;
105 pszKey
= pszParameter
;
110 blnBadParameter
= TRUE
;
114 rConsole
.Write(_T("Bad parameter: "));
115 rConsole
.Write(pszParameter
);
116 rConsole
.Write(_T("\n"));
122 ASSERT(hThreadToken
== INVALID_HANDLE_VALUE
);
125 if (!OpenThreadToken(GetCurrentThread(),TOKEN_ADJUST_PRIVILEGES
|TOKEN_QUERY
,FALSE
,&hThreadToken
))
126 { // OpenThreadToken failed
127 dwError
= GetLastError();
128 if (dwError
!= ERROR_NO_TOKEN
)
130 _sntprintf(pszError_msg
,ERROR_MSG_BUFFER_SIZE
-1,_T("\nCannot open thread token.\nOpenThreadToken fails with error: %u\n"),(unsigned int)dwError
);
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
))
138 _sntprintf(pszError_msg
,ERROR_MSG_BUFFER_SIZE
-1,_T("\nCannot open process token.\nOpenProcessToken fails with error: %u\n"),(unsigned int)GetLastError());
143 ASSERT(hThreadToken
!= INVALID_HANDLE_VALUE
);
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
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());
159 blnAdjRet
= AdjustTokenPrivileges(
163 sizeof(TOKEN_PRIVILEGES
),
164 (PTOKEN_PRIVILEGES
)NULL
,
166 dwError
= GetLastError();
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(""));
173 if (dwError
!= ERROR_SUCCESS
)
175 if (dwError
== ERROR_NOT_ALL_ASSIGNED
)
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
);
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
);
187 if (!m_rTree
.GetKey(pszKey
?pszKey
:_T("."),KEY_QUERY_VALUE
|READ_CONTROL
|ACCESS_SYSTEM_SECURITY
,Key
))
189 rConsole
.Write(m_rTree
.GetLastErrorDescription());
195 rConsole
.Write(GetHelpString());
199 rConsole
.Write(_T("\n"));
206 _tcsncpy(pszError_msg
,SACL_CMD COMMAND_NA_ON_ROOT
,ERROR_MSG_BUFFER_SIZE
-1);
210 DWORD dwSecurityDescriptorLength
;
211 rConsole
.Write(_T("Key : "));
212 rConsole
.Write(_T("\\"));
214 rConsole
.Write(Key
.GetKeyName());
215 rConsole
.Write(_T("\n"));
216 dwError
= Key
.GetSecurityDescriptorLength(&dwSecurityDescriptorLength
);
217 if (dwError
!= ERROR_SUCCESS
)
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
);
223 pSecurityDescriptor
= (PISECURITY_DESCRIPTOR
) new (std::nothrow
) unsigned char [dwSecurityDescriptorLength
];
224 if (!pSecurityDescriptor
)
226 _tcsncpy(pszError_msg
,_T("\nOut of memory.\n"),ERROR_MSG_BUFFER_SIZE
-1);
230 DWORD dwSecurityDescriptorLength1
;
231 dwSecurityDescriptorLength1
= dwSecurityDescriptorLength
;
232 dwError
= Key
.GetSecurityDescriptor((SECURITY_INFORMATION
)SACL_SECURITY_INFORMATION
,pSecurityDescriptor
,&dwSecurityDescriptorLength1
);
233 if (dwError
!= ERROR_SUCCESS
)
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(""));
239 sd
.AssociateDescriptor(pSecurityDescriptor
);
240 sd
.BeginSACLInteration();
242 if ((!sd
.DescriptorContainsSACL())||(sd
.HasNULLSACL()))
244 _tcsncpy(pszError_msg
,_T("Key has not SACL.\n"),ERROR_MSG_BUFFER_SIZE
-1);
248 if (!sd
.HasValidSACL())
250 _tcsncpy(pszError_msg
,_T("Invalid SACL.\n"),ERROR_MSG_BUFFER_SIZE
-1);
255 nACECount
= sd
.GetSACLEntriesCount();
256 rConsole
.Write(_T("SACL has "));
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
++)
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
)
272 rConsole
.Write(_T("Unknown ACE type.\nCannot continue ACE list dump.\n"));
277 rConsole
.Write(_T("Failed access"));
279 if (blnFailed
&& blnSuccessful
)
280 rConsole
.Write(_T(" & "));
282 rConsole
.Write(_T("Successful access"));
283 rConsole
.Write(_T("\n"));
285 PSID pSID
= sd
.GetCurrentACE_SID();
286 if ((pSID
== NULL
)||(!IsValidSid(pSID
)))
288 rConsole
.Write(_T("\tInvalid SID.\n"));
291 DWORD dwSIDStringSize
= 0;
292 BOOL blnRet
= GetTextualSid(pSID
,NULL
,&dwSIDStringSize
);
294 ASSERT(GetLastError() == ERROR_INSUFFICIENT_BUFFER
);
295 TCHAR
*pszSID
= new (std::nothrow
) TCHAR
[dwSIDStringSize
];
299 _tcsncpy(pszError_msg
,_T("\nOut of memory.\n"),ERROR_MSG_BUFFER_SIZE
-1);
303 if(!GetTextualSid(pSID
,pszSID
,&dwSIDStringSize
))
305 dwError
= GetLastError();
306 ASSERT(dwError
!= ERROR_INSUFFICIENT_BUFFER
);
307 rConsole
.Write(_T("Error "));
309 rConsole
.Write(_itoa(dwError
,Buffer
,10));
310 rConsole
.Write(_T("\nGetting string representation of SID\n"));
314 rConsole
.Write(_T("\tSID: "));
315 rConsole
.Write(pszSID
);
316 rConsole
.Write(_T("\n"));
320 TCHAR
*pszName
, *pszDomainName
;
321 DWORD dwNameBufferLength
, dwDomainNameBufferLength
;
322 dwNameBufferLength
= 1024;
323 dwDomainNameBufferLength
= 1024;
325 pszName
= new (std::nothrow
) TCHAR
[dwNameBufferLength
];
328 _tcsncpy(pszError_msg
,_T("\nOut of memory.\n"),ERROR_MSG_BUFFER_SIZE
-1);
332 pszDomainName
= new (std::nothrow
) TCHAR
[dwDomainNameBufferLength
];
335 _tcsncpy(pszError_msg
,_T("\nOut of memory.\n"),ERROR_MSG_BUFFER_SIZE
-1);
340 DWORD dwNameLength
= dwNameBufferLength
, dwDomainNameLength
= dwDomainNameBufferLength
;
342 if (!LookupAccountSid(NULL
,pSID
,pszName
,&dwNameLength
,pszDomainName
,&dwDomainNameLength
,&Use
))
344 rConsole
.Write(_T("Error "));
346 rConsole
.Write(_itoa(GetLastError(),Buffer
,10));
347 rConsole
.Write(_T("\n"));
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"));
361 sd
.GetCurrentACE_AccessMask(dwAccessMask
);
362 wsprintf(Buffer
,_T("\tAccess Mask: 0x%08lX\n"),dwAccessMask
);
363 rConsole
.Write(Buffer
);
364 if (dwAccessMask
& GENERIC_READ
)
366 rConsole
.Write(_T("\t\tGENERIC_READ\n"));
368 if (dwAccessMask
& GENERIC_WRITE
)
370 rConsole
.Write(_T("\t\tGENERIC_WRITE\n"));
372 if (dwAccessMask
& GENERIC_EXECUTE
)
374 rConsole
.Write(_T("\t\tGENERIC_EXECUTE\n"));
376 if (dwAccessMask
& GENERIC_ALL
)
378 rConsole
.Write(_T("\t\tGENERIC_ALL\n"));
380 if (dwAccessMask
& SYNCHRONIZE
)
382 rConsole
.Write(_T("\t\tSYNCHRONIZE\n"));
384 if (dwAccessMask
& WRITE_OWNER
)
386 rConsole
.Write(_T("\t\tWRITE_OWNER\n"));
388 if (dwAccessMask
& WRITE_DAC
)
390 rConsole
.Write(_T("\t\tWRITE_DAC\n"));
392 if (dwAccessMask
& READ_CONTROL
)
394 rConsole
.Write(_T("\t\tREAD_CONTROL\n"));
396 if (dwAccessMask
& DELETE
)
398 rConsole
.Write(_T("\t\tDELETE\n"));
400 if (dwAccessMask
& KEY_CREATE_LINK
)
402 rConsole
.Write(_T("\t\tKEY_CREATE_LINK\n"));
404 if (dwAccessMask
& KEY_NOTIFY
)
406 rConsole
.Write(_T("\t\tKEY_NOTIFY\n"));
408 if (dwAccessMask
& KEY_ENUMERATE_SUB_KEYS
)
410 rConsole
.Write(_T("\t\tKEY_ENUMERATE_SUB_KEYS\n"));
412 if (dwAccessMask
& KEY_CREATE_SUB_KEY
)
414 rConsole
.Write(_T("\t\tKEY_CREATE_SUB_KEY\n"));
416 if (dwAccessMask
& KEY_SET_VALUE
)
418 rConsole
.Write(_T("\t\tKEY_SET_VALUE\n"));
420 if (dwAccessMask
& KEY_QUERY_VALUE
)
422 rConsole
.Write(_T("\t\tKEY_QUERY_VALUE\n"));
426 delete[] pszDomainName
;
430 ASSERT(pSecurityDescriptor
);
431 delete pSecurityDescriptor
;
433 VERIFY(CloseHandle(hThreadToken
));
437 if (pSecurityDescriptor
)
438 delete pSecurityDescriptor
;
440 if (hThreadToken
!= INVALID_HANDLE_VALUE
)
441 VERIFY(CloseHandle(hThreadToken
));
443 rConsole
.Write(pszError_msg
);
447 const TCHAR
* CShellCommandSACL::GetHelpString()
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");
456 const TCHAR
* CShellCommandSACL::GetHelpShortDescriptionString()
458 return SACL_CMD_SHORT_DESC
;