//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1999. // // File: ChkDeleg.cpp // // Contents: CheckDelegation and support methods // // //---------------------------------------------------------------------------- #include "stdafx.h" #include #include #include "adutils.h" #include #include "ChkDeleg.h" #include #include #include "SecDesc.h" #include #include // from the admin\display project (CrackName) #ifndef ARRAYSIZE #define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0])) #endif #include <_util.cpp> #include <_tempcor.cpp> #include <_deltemp.cpp> class CTemplateAccessPermissionsHolderManagerVerify : public CTemplateAccessPermissionsHolderManager { public: HRESULT ProcessTemplates (); // for ACLDiag - process each template in turn HRESULT ProcessPermissions( const wstring& strObjectClass, CTemplate* pTemplate, PACL pAccessList, CPrincipalList& principalList); }; HRESULT CheckDelegation () { _TRACE (1, L"Entering CheckDelegation\n"); HRESULT hr = S_OK; wstring str; if ( !_Module.DoTabDelimitedOutput () ) { LoadFromResource (str, IDS_DELEGATION_TEMPLATE_DIAGNOSIS); MyWprintf (str.c_str ()); } CTemplateAccessPermissionsHolderManagerVerify templateAccessPermissionsHolderManager; if ( templateAccessPermissionsHolderManager.LoadTemplates() ) { hr = templateAccessPermissionsHolderManager.ProcessTemplates (); } else { LoadFromResource (str, IDS_FAILED_TO_LOAD_TEMPLATES); MyWprintf (str.c_str ()); hr = E_FAIL; } _TRACE (-1, L"Leaving CheckDelegation: 0x%x\n", hr); return hr; } PTOKEN_USER EfspGetTokenUser () { _TRACE (1, L"Entering EfspGetTokenUser\n"); HANDLE hToken = 0; DWORD dwReturnLength = 0; PTOKEN_USER pTokenUser = NULL; BOOL bResult = ::OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &hToken); if ( bResult ) { bResult = ::GetTokenInformation ( hToken, TokenUser, NULL, 0, &dwReturnLength ); if ( !bResult && dwReturnLength > 0 ) { pTokenUser = (PTOKEN_USER) malloc (dwReturnLength); if (pTokenUser) { bResult = GetTokenInformation ( hToken, TokenUser, pTokenUser, dwReturnLength, &dwReturnLength ); if ( !bResult) { DWORD dwErr = GetLastError (); _TRACE (0, L"GetTokenInformation () failed: 0x%x\n", dwErr); free (pTokenUser); pTokenUser = NULL; } } } else { DWORD dwErr = GetLastError (); _TRACE (0, L"GetTokenInformation () failed: 0x%x\n", dwErr); } ::CloseHandle (hToken); } else { DWORD dwErr = GetLastError (); _TRACE (0, L"OpenProcessToken () failed: 0x%x\n", dwErr); } _TRACE (-1, L"Leaving EfspGetTokenUser\n"); return pTokenUser; } HRESULT CTemplateAccessPermissionsHolderManagerVerify::ProcessTemplates () { HRESULT hr = S_OK; DWORD dwErr = 0; // the access list is read in, modified, written back // If /fixdeleg is on, this list will be populated from the DS, // will receive the permissions associated with selected templates is the // user chooses to fix delegation, and then will be written back to the DS. PACL pFixDACL = NULL; LPCWSTR lpszObjectLdapPath = _Module.m_adsiObject.GetLdapPath(); // get the security info if ( _Module.FixDelegation () && !_Module.DoTabDelimitedOutput () ) { _TRACE (0, L"calling GetNamedSecurityInfo(%s, ...)\n", lpszObjectLdapPath); dwErr = ::GetNamedSecurityInfo ( (LPWSTR) lpszObjectLdapPath, // name of the object SE_DS_OBJECT_ALL, // type of object DACL_SECURITY_INFORMATION, // type of security information to retrieve NULL, // receives a pointer to the owner SID NULL, // receives a pointer to the primary group SID &pFixDACL, // receives a pointer to the DACL NULL, // receives a pointer to the SACL NULL); // receives a pointer to the security descriptor if (dwErr != ERROR_SUCCESS) { _TRACE (0, L"failed on GetNamedSecurityInfo(): dwErr = 0x%x\n", dwErr); wstring str; LoadFromResource (str, IDS_DELEGWIZ_ERR_GET_SEC_INFO); MyWprintf (str.c_str ()); _Module.TurnOffFixDelegation (); } } CPrincipal principal; // a dummy placeholder for us to get // the incremental rights associated // with each template // We will use the current logged-in user as a placeholder only. PTOKEN_USER pTokenUser = ::EfspGetTokenUser (); if ( pTokenUser ) { hr = principal.Initialize (pTokenUser->User.Sid); free (pTokenUser); } if ( SUCCEEDED (hr) ) { CTemplateList* pList = m_templateManager.GetTemplateList(); for (CTemplateList::iterator itr = pList->begin(); itr != pList->end(); itr++) { CTemplate* pTemplate = *itr; ASSERT(pTemplate != NULL); // Select the templates one at a time to get the // permissions representing them pTemplate->m_bSelected = TRUE; if ( InitPermissionHoldersFromSelectedTemplates ( &_Module.m_classInfoArray, &_Module.m_adsiObject) ) { // This access list will contain only the access control values // associated with the selected template PACL pAccessList = 0; //(PACL) ::LocalAlloc (LMEM_ZEROINIT, sizeof (ACL)); if ( 1 ) //pAccessList ) { DWORD dwErr = UpdateAccessList ( &principal, _Module.m_adsiObject.GetServerName(), _Module.m_adsiObject.GetPhysicalSchemaNamingContext(), &pAccessList ); if ( 0 == dwErr ) { CPrincipalList principalList; PSID pSid = principal.GetSid (); SID_NAME_USE sne = SidTypeUnknown; wstring strPrincipalName; hr = GetNameFromSid (pSid, strPrincipalName, 0, sne); if ( SUCCEEDED (hr) ) { hr = ProcessPermissions (_Module.m_adsiObject.GetClass (), pTemplate, pAccessList, principalList); if ( SUCCEEDED (hr) && _Module.FixDelegation () && !_Module.DoTabDelimitedOutput () ) { // loop thru all the principals and classes CPrincipalList::iterator i; for (i = principalList.begin(); i != principalList.end(); ++i) { CPrincipal* pCurrPrincipal = (*i); dwErr = UpdateAccessList( pCurrPrincipal, _Module.m_adsiObject.GetServerName(), _Module.m_adsiObject.GetPhysicalSchemaNamingContext(), &pFixDACL); if (dwErr != 0) break; } // for pCurrPrincipal } } } ::LocalFree (pAccessList); } else { hr = E_OUTOFMEMORY; break; } } pTemplate->m_bSelected = FALSE; } if ( _Module.FixDelegation () && !_Module.DoTabDelimitedOutput () ) { // commit changes _TRACE (0, L"calling SetNamedSecurityInfo(%s, ...)\n", lpszObjectLdapPath); dwErr = ::SetNamedSecurityInfoW( (LPWSTR) lpszObjectLdapPath, SE_DS_OBJECT_ALL, DACL_SECURITY_INFORMATION, NULL, NULL, pFixDACL, 0); if (dwErr != ERROR_SUCCESS) { _TRACE (0, L"failed on SetNamedSecurityInfo(): dwErr = 0x%x\n", dwErr); wstring str; LoadFromResource (str, IDS_DELEGWIZ_ERR_SET_SEC_INFO); MyWprintf (str.c_str ()); } } } if ( pFixDACL ) ::LocalFree (pFixDACL); return hr; } class CTemplateStatus { public: CTemplateStatus () : m_nACECnt (1), m_bApplies (false), m_bInherited (false) { } ULONG m_nACECnt; bool m_bApplies; bool m_bInherited; wstring m_strObjName; PSID m_psid; }; typedef list CStatusList; HRESULT CTemplateAccessPermissionsHolderManagerVerify::ProcessPermissions( const wstring& strObjectClass, CTemplate* pTemplate, PACL pDacl, CPrincipalList& principalList) { if ( !pTemplate ) return E_POINTER; HRESULT hr = S_OK; CStatusList statusList; // This list will contain 1 entry for each // SidStart/bInherited/bApplies triplet. // The counter for each item will incremented // each time an ACE is found that belongs to // the object pointed to by the SidStart. ULONG nExpectedCnt = 0; bool bApplies = pTemplate->AppliesToClass(strObjectClass.c_str ()) ? true : false; ACE_SAMNAME* pAceSAMName = 0; // Look in global DACL for each right PACCESS_ALLOWED_ACE pAllowedAce = 0; // iterate through the template ACES for (int i = 0; i < pDacl->AceCount; i++) { if ( GetAce (pDacl, i, (void **)&pAllowedAce) ) { PSID AceSid = 0; if ( IsObjectAceType ( pAllowedAce ) ) { AceSid = RtlObjectAceSid( pAllowedAce ); } else { AceSid = &( ( PKNOWN_ACE )pAllowedAce )->SidStart; } ASSERT (IsValidSid (AceSid)); if ( !IsValidSid (AceSid) ) continue; // wstring strPrincipalName; // SID_NAME_USE sne = SidTypeUnknown; // hr = GetNameFromSid (AceSid, strPrincipalName, 0, sne); // if ( SUCCEEDED (hr) ) { ACE_SAMNAME* pAceTemplate = new ACE_SAMNAME; if ( pAceTemplate ) { pAceTemplate->m_AceType = pAllowedAce->Header.AceType; switch (pAceTemplate->m_AceType) { case ACCESS_ALLOWED_ACE_TYPE: pAceTemplate->m_pAllowedAce = pAllowedAce; break; case ACCESS_ALLOWED_OBJECT_ACE_TYPE: pAceTemplate->m_pAllowedObjectAce = reinterpret_cast (pAllowedAce); break; case ACCESS_DENIED_ACE_TYPE: pAceTemplate->m_pDeniedAce = reinterpret_cast (pAllowedAce); break; case ACCESS_DENIED_OBJECT_ACE_TYPE: pAceTemplate->m_pDeniedObjectAce = reinterpret_cast (pAllowedAce); break; default: break; } // pAceTemplate->m_SAMAccountName = strPrincipalName; pAceTemplate->DebugOut (); nExpectedCnt++; ACE_SAMNAME_LIST::iterator itr = _Module.m_DACLList.begin (); for (; itr != _Module.m_DACLList.end () && SUCCEEDED (hr); itr++) { pAceSAMName = *itr; // to neutralize Sid differences pAceTemplate->m_SAMAccountName = pAceSAMName->m_SAMAccountName; if ( *pAceSAMName == *pAceTemplate ) { bool bFound = false; CTemplateStatus* pStatus = 0; CStatusList::iterator itr = statusList.begin (); wstring strObjName; PSID psid = 0; if ( ACCESS_ALLOWED_OBJECT_ACE_TYPE == pAceSAMName->m_AceType ) { psid = RtlObjectAceSid (pAceSAMName->m_pAllowedObjectAce); } else { psid = &( ( PKNOWN_ACE )pAceSAMName->m_pAllowedAce )->SidStart; } SID_NAME_USE sne = SidTypeUnknown; hr = GetNameFromSid (psid, strObjName, 0, sne); if ( SUCCEEDED (hr) ) { for (; itr != statusList.end (); itr++) { pStatus = *itr; if ( (pStatus->m_bApplies == bApplies) && ( pStatus->m_bInherited == pAceSAMName->IsInherited () ) && ( !_wcsicmp ( pStatus->m_strObjName.c_str (), strObjName.c_str ())) ) { bFound = true; break; } } if ( bFound ) { pStatus->m_nACECnt++; } else { pStatus = new CTemplateStatus; if ( pStatus ) { pStatus->m_strObjName = strObjName; pStatus->m_bApplies = bApplies; pStatus->m_bInherited = pAceSAMName->IsInherited (); pStatus->m_psid = psid; statusList.push_back (pStatus); } else { hr = E_OUTOFMEMORY; break; } } } } } } else { hr = E_OUTOFMEMORY; break; } } } } // Now, iterate thru status list and evaluate each item // If the list is empty, then this template is not present. // Otherwise, for each present item, if the class and attr count is less than the required count // the template is partial for the item. // Otherwise, it is OK. CStatusList::iterator itr = statusList.begin (); CTemplateStatus* pStatus = 0; wstring str; wstring strStatus; for (; itr != statusList.end () && SUCCEEDED (hr); itr++) { pStatus = *itr; // Print template description bool bMisconfigured = false; if ( _Module.DoTabDelimitedOutput () ) { FormatMessage (str, IDS_DELEGATION_TITLE_CDO, pTemplate->GetDescription (), pStatus->m_strObjName.c_str ()); } else { FormatMessage (str, IDS_DELEGATION_TITLE, pTemplate->GetDescription (), pStatus->m_strObjName.c_str ()); } MyWprintf (str.c_str ()); // Print "Status: OK/MISCONFIGURED" if ( pStatus->m_nACECnt < nExpectedCnt ) { LoadFromResource (strStatus, IDS_MISCONFIGURED); bMisconfigured = true; } else LoadFromResource (strStatus, IDS_OK); if ( _Module.DoTabDelimitedOutput () ) FormatMessage (str, IDS_DELTEMPL_STATUS_CDO, strStatus.c_str ()); else FormatMessage (str, IDS_DELTEMPL_STATUS, strStatus.c_str ()); MyWprintf (str.c_str ()); // Print "Applies on this object: YES/NO" if ( pStatus->m_bApplies ) { LoadFromResource (strStatus, _Module.DoTabDelimitedOutput () ? IDS_APPLIES : IDS_YES); } else { LoadFromResource (strStatus, _Module.DoTabDelimitedOutput () ? IDS_DOES_NOT_APPLY : IDS_NO); } if ( _Module.DoTabDelimitedOutput () ) FormatMessage (str, IDS_APPLIES_ON_THIS_OBJECT_CDO, strStatus.c_str ()); else FormatMessage (str, IDS_APPLIES_ON_THIS_OBJECT, strStatus.c_str ()); MyWprintf (str.c_str ()); // Print "Inherited from parent: YES/NO" if ( pStatus->m_bInherited ) { LoadFromResource (strStatus, _Module.DoTabDelimitedOutput () ? IDS_INHERITED : IDS_YES); } else { LoadFromResource (strStatus, _Module.DoTabDelimitedOutput () ? IDS_EXPLICIT : IDS_NO); } if ( _Module.DoTabDelimitedOutput () ) FormatMessage (str, IDS_INHERITED_FROM_PARENT_CDO, strStatus.c_str ()); else FormatMessage (str, IDS_INHERITED_FROM_PARENT, strStatus.c_str ()); MyWprintf (str.c_str ()); if ( bMisconfigured && _Module.FixDelegation () && !_Module.DoTabDelimitedOutput () ) { LoadFromResource (str, IDS_FIX_DELEGATION_QUERY); while (1) { MyWprintf (str.c_str ()); int ch = _getche (); if ( 'y' == ch ) { CPrincipal* pPrincipal = new CPrincipal; if ( pPrincipal ) { if ( SUCCEEDED (pPrincipal->Initialize (pStatus->m_psid)) ) principalList.push_back (pPrincipal); else delete pPrincipal; } else hr = E_OUTOFMEMORY; MyWprintf (L"\n\n"); break; } else if ( 'n' == ch ) { MyWprintf (L"\n\n"); break; } else { MyWprintf (L"\n"); continue; } } } } if ( !pStatus ) // None found { // Print template description if ( _Module.DoTabDelimitedOutput () ) { FormatMessage (str, IDS_DELEGATION_NOT_FOUND_CDO, pTemplate->GetDescription ()); MyWprintf (str.c_str ()); } else { FormatMessage (str, L"\t%1\n\n", pTemplate->GetDescription ()); MyWprintf (str.c_str ()); LoadFromResource (strStatus, IDS_NOT_PRESENT); FormatMessage (str, IDS_DELTEMPL_STATUS, strStatus.c_str ()); MyWprintf (str.c_str ()); } } if ( !_Module.DoTabDelimitedOutput () ) MyWprintf (L"\n"); return hr; }