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 } 459