/*****************************************************************************/ /* Copyright (c) 1999-2001 Microsoft Corporation, All Rights Reserved / /*****************************************************************************/ //================================================================= // // SecUtils.cpp -- Security utilities useful to wbem mof classes // // Copyright (c) 1999-2001 Microsoft Corporation, All Rights Reserved // // Revisions: 6/9/99 a-kevhu Created // //================================================================= #include "precomp.h" #include #include "AccessEntry.h" // CAccessEntry class #include "AccessEntryList.h" #include "DACL.h" // CDACL class #include "SACL.h" #include "SecurityDescriptor.h" #include #include "AccessRights.h" #include "SecureFile.h" #include "SecureShare.h" #include "wbemnetapi32.h" #include "SecUtils.h" /////////////////////////////////////////////////////////////////// // // Function: FillTrusteeFromSid // // Default class constructor. // // Inputs: // None. // // Outputs: // None. // // Returns: // None. // // Comments: // /////////////////////////////////////////////////////////////////// void FillTrusteeFromSid (CInstance *pInstance, CSid &sid) { if (pInstance) { PSID pSid; CHString chstrName; CHString chstrDomain; VARIANT vValue; if (sid.IsValid()) { pSid = sid.GetPSid(); chstrName = sid.GetAccountName(); chstrDomain = sid.GetDomainName(); // set the UINT8 array for the pSid DWORD dwSidLength = sid.GetLength(); // BYTE bByte; SAFEARRAY* sa; SAFEARRAYBOUND rgsabound[1]; VariantInit(&vValue); rgsabound[0].cElements = dwSidLength; PSID pSidTrustee = NULL ; rgsabound[0].lLbound = 0; sa = SafeArrayCreate(VT_UI1, 1, rgsabound); // Get a pointer to read the data into SafeArrayAccessData(sa, &pSidTrustee); memcpy(pSidTrustee, pSid, rgsabound[0].cElements); SafeArrayUnaccessData(sa); // Put the safearray into a variant, and send it off V_VT(&vValue) = VT_UI1 | VT_ARRAY; V_ARRAY(&vValue) = sa; pInstance->SetVariant(IDS_Sid, vValue); VariantClear(&vValue); // fill in the rest of the stuff. if(!chstrName.IsEmpty()) { pInstance->SetCHString(IDS_Name, chstrName); } if(!chstrDomain.IsEmpty()) { pInstance->SetCHString(IDS_Domain, chstrDomain); } pInstance->SetDWORD(IDS_SidLength, dwSidLength); // Fill in the SIDString property... pInstance->SetCHString(IDS_SIDString, sid.GetSidString()); } } } /////////////////////////////////////////////////////////////////// // // Function: FillInstanceDACL // // Default class constructor. // // Inputs: // None. // // Outputs: // None. // // Returns: // None. // // Comments: // /////////////////////////////////////////////////////////////////// void FillInstanceDACL(CInstance *pInstance, CDACL &dacl) { CAccessEntry ace; SAFEARRAY* saDACL; SAFEARRAYBOUND rgsabound[1]; VARIANT vValue; if ( pInstance && !dacl.IsEmpty() ) { // First need merged list... CAccessEntryList t_cael; if(dacl.GetMergedACL(t_cael)) { DWORD dwSize; long ix[1]; dwSize = t_cael.NumEntries(); rgsabound[0].cElements = dwSize; rgsabound[0].lLbound = 0; saDACL = SafeArrayCreate(VT_UNKNOWN, 1, rgsabound); ix[0] = 0; ACLPOSITION pos; t_cael.BeginEnum(pos); while (t_cael.GetNext(pos, ace)) { CInstancePtr pAce; CInstancePtr pTrustee; // now that we have the ACE, let's create a Win32_ACE object so we can // add it to the embedded object list. if (SUCCEEDED(CWbemProviderGlue::GetEmptyInstance(pInstance->GetMethodContext(), L"Win32_Ace", &pAce, IDS_CimWin32Namespace ) ) ) { // fill trustee from SID CSid sid; ace.GetSID(sid); if (SUCCEEDED(CWbemProviderGlue::GetEmptyInstance(pInstance->GetMethodContext(), L"Win32_Trustee", &pTrustee, IDS_CimWin32Namespace ))) { FillTrusteeFromSid(pTrustee, sid); pAce->SetEmbeddedObject(IDS_Trustee, *pTrustee); // pTrustee->Release() ; } // end if DWORD dwAceType = ace.GetACEType(); DWORD dwAceFlags = ace.GetACEFlags(); DWORD dwAccessMask = ace.GetAccessMask (); pAce->SetDWORD(IDS_AceType, dwAceType); pAce->SetDWORD(IDS_AceFlags, dwAceFlags); pAce->SetDWORD(IDS_AccessMask, dwAccessMask); #ifdef NTONLY #if NTONLY > 5 // fill Guids GUID guidObjType, guidInhObjType; if(ace.GetObjType(guidObjType)) { WCHAR wstrGuid[39]; if(::StringFromGUID2(&guidObjType, wstrGuid, 39)) { pAce->SetWCHARSplat(IDS_GuidObjectType, wstrGuid); } } if(ace.GetInhObjType(guidInhObjType)) { WCHAR wstrGuid[39]; if(::StringFromGUID2(&guidInhObjType, wstrGuid, 39)) { pAce->SetWCHARSplat(IDS_GuidInheritedObjectType, wstrGuid); } } #endif #endif // Get the IUnknown of the Win32_ACE object. Convert it to a // variant of type VT_UNKNOWN. Then, add the variant to the // SafeArray. Eventually, to add the list to the actual // Win32_SecurityDescriptor object, we will be using SetVariant. // Note: it is intentional that we are not decrementing the Addref // done on pAce by the following call. IWbemClassObjectPtr pClassObject(pAce->GetClassObjectInterface()); if ( pClassObject ) { VARIANT v; VariantInit(&v); v.vt = VT_UNKNOWN; v.punkVal = pClassObject ; SafeArrayPutElement(saDACL, ix, pClassObject); VariantClear(&v); } // end if } // end if ix[0]++ ; } // end while VariantInit(&vValue); V_VT(&vValue) = VT_UNKNOWN | VT_ARRAY; V_ARRAY(&vValue) = saDACL; pInstance->SetVariant(IDS_DACL, vValue); VariantClear(&vValue); t_cael.EndEnum(pos); } } } /////////////////////////////////////////////////////////////////// // // Function: FillInstanceSACL // // Default class constructor. // // Inputs: // None. // // Outputs: // None. // // Returns: // None. // // Comments: // /////////////////////////////////////////////////////////////////// void FillInstanceSACL(CInstance *pInstance, CSACL &sacl) { CAccessEntry ace; CInstancePtr pAce; CInstancePtr pTrustee; SAFEARRAY* saSACL; SAFEARRAYBOUND rgsabound[1]; VARIANT vValue; if ( pInstance && !sacl.IsEmpty() ) { // First need merged list... CAccessEntryList t_cael; if(sacl.GetMergedACL(t_cael)) { DWORD dwSize; long ix[1]; dwSize = t_cael.NumEntries(); rgsabound[0].cElements = dwSize; rgsabound[0].lLbound = 0; saSACL = SafeArrayCreate(VT_UNKNOWN, 1, rgsabound); ix[0] = 0; ACLPOSITION pos; t_cael.BeginEnum(pos); while (t_cael.GetNext(pos, ace)) { // now that we have the ACE, let's create a Win32_ACE object so we can // add it to the embedded object list. if (SUCCEEDED(CWbemProviderGlue::GetEmptyInstance(pInstance->GetMethodContext(), L"Win32_Ace", &pAce, IDS_CimWin32Namespace))) { // fill trustee from SID CSid sid; ace.GetSID(sid); if (SUCCEEDED(CWbemProviderGlue::GetEmptyInstance(pInstance->GetMethodContext(), L"Win32_Trustee", &pTrustee, IDS_CimWin32Namespace ))) { FillTrusteeFromSid(pTrustee, sid); pAce->SetEmbeddedObject(IDS_Trustee, *pTrustee); } // end if DWORD dwAceType = ace.GetACEType(); DWORD dwAceFlags = ace.GetACEFlags(); DWORD dwAccessMask = ace.GetAccessMask (); pAce->SetDWORD(IDS_AceType, dwAceType); pAce->SetDWORD(IDS_AceFlags, dwAceFlags); pAce->SetDWORD(IDS_AccessMask, dwAccessMask); #ifdef NTONLY #if NTONLY > 5 // fill Guids GUID guidObjType, guidInhObjType; if(ace.GetObjType(guidObjType)) { WCHAR wstrGuid[39]; if(::StringFromGUID2(&guidObjType, wstrGuid, 39)) { pAce->SetWCHARSplat(IDS_GuidObjectType, wstrGuid); } } if(ace.GetInhObjType(guidInhObjType)) { WCHAR wstrGuid[39]; if(::StringFromGUID2(&guidInhObjType, wstrGuid, 39)) { pAce->SetWCHARSplat(IDS_GuidInheritedObjectType, wstrGuid); } } #endif #endif // Get the IUnknown of the Win32_ACE object. Convert it to a // variant of type VT_UNKNOWN. Then, add the variant to the // SafeArray. Eventually, to add the list to the actual // Win32_SecurityDescriptor object, we will be using SetVariant IWbemClassObjectPtr pClassObject(pAce->GetClassObjectInterface()); if ( pClassObject ) { VARIANT v; VariantInit(&v); v.vt = VT_UNKNOWN; v.punkVal = pClassObject ; SafeArrayPutElement(saSACL, ix, pClassObject); VariantClear(&v); } // end if } // end if ix[0]++ ; } // end while VariantInit(&vValue); V_VT(&vValue) = VT_UNKNOWN | VT_ARRAY; V_ARRAY(&vValue) = saSACL; pInstance->SetVariant(IDS_SACL, vValue); VariantClear(&vValue); t_cael.EndEnum(pos); } } } /////////////////////////////////////////////////////////////////// // // Function: FillDACLFromInstance // // Default class constructor. // // Inputs: // None. // // Outputs: // None. // // Returns: // None. // // Comments: // /////////////////////////////////////////////////////////////////// DWORD FillDACLFromInstance(CInstance *pInstance, CDACL &dacl, MethodContext *pMethodContext) { IWbemClassObjectPtr piClassObject; piClassObject.Attach(pInstance->GetClassObjectInterface()); DWORD dwStatus = ERROR_SUCCESS ; if(piClassObject) { VARIANT vDacl ; if(GetArray(piClassObject,IDS_DACL, vDacl, VT_UNKNOWN|VT_ARRAY) ) { if( vDacl.vt != VT_NULL && vDacl.parray != NULL ) { // walk DACL LONG lDimension = 1 ; LONG lLowerBound ; SafeArrayGetLBound ( vDacl.parray , lDimension , &lLowerBound ) ; LONG lUpperBound ; SafeArrayGetUBound ( vDacl.parray , lDimension , &lUpperBound ) ; for ( LONG lIndex = lLowerBound ; lIndex <= lUpperBound ; lIndex++ ) { if( dwStatus != ERROR_SUCCESS ) { break ; } IWbemClassObjectPtr pACEObject; SafeArrayGetElement ( vDacl.parray , &lIndex , &pACEObject ) ; // take out IWbemClassObject and cast it to a Win32_ACE object. if(pACEObject) { CInstance ACEInstance(pACEObject, pMethodContext); // create an AccessEntry object from the Win32_ACE object. bool bExists =false ; VARTYPE eType ; // get Win32_Trustee object from Win32_ACE ...& decipher the ACE if ( ACEInstance.GetStatus ( IDS_Trustee, bExists , eType ) && bExists && eType == VT_UNKNOWN ) { CInstancePtr pTrustee; if ( ACEInstance.GetEmbeddedObject ( IDS_Trustee, &pTrustee, ACEInstance.GetMethodContext() ) ) { CSid sid ; if((dwStatus = FillSIDFromTrustee(pTrustee, sid)) == ERROR_SUCCESS) { DWORD dwAceType, dwAceFlags, dwAccessMask ; CHString chstrInhObjGuid; GUID *pguidInhObjGuid = NULL; CHString chstrObjGuid; GUID *pguidObjGuid = NULL; ACEInstance.GetDWORD(IDS_AceType, dwAceType); ACEInstance.GetDWORD(IDS_AceFlags, dwAceFlags); ACEInstance.GetDWORD(IDS_AccessMask, dwAccessMask); // The OS doesn't seem to support 0x01000000 or 0x02000000, so we won't either. We // will translate 0x02000000 into FILE_ALL_ACCESS, however (seems like the nice thing to do) // but only if that is the exact value they set. if(dwAccessMask == 0x02000000) { dwAccessMask = FILE_ALL_ACCESS; } #if NTONLY >= 5 // On NT5 and greater, if the user specified an ACE with the Ace Flag bit INHERIT_ACE set, // the OS will make these local, not inherited ACE entries. However, the OS will not reorder // the DACL, possibly resulting in a situation in which denied ACEs (that had been inherited) // follow allowed ACEs. // So if the Ace flags specify INHERITED_ACE, we need to turn // off this bit... dwAceFlags &= ~INHERITED_ACE; #endif if(!(dwAceFlags & INHERITED_ACE)) { switch (dwAceType) { case ACCESS_DENIED_ACE_TYPE: { dacl.AddDACLEntry( sid.GetPSid(), ENUM_ACCESS_DENIED_ACE_TYPE, dwAccessMask, dwAceFlags, NULL, NULL ); break; } case ACCESS_ALLOWED_ACE_TYPE: { dacl.AddDACLEntry( sid.GetPSid(), ENUM_ACCESS_ALLOWED_ACE_TYPE, dwAccessMask, dwAceFlags, NULL, NULL ); break; } #if NTONLY >= 5 // Not yet supported under W2K //case ACCESS_ALLOWED_COMPOUND_ACE_TYPE: // { // dacl.AddDACLEntry( sid.GetPSid(), ENUM_ACCESS_ALLOWED_COMPOUND_ACE_TYPE, dwAccessMask, dwAceFlags, NULL, NULL ); // break; // } case ACCESS_DENIED_OBJECT_ACE_TYPE: { // Need to get the guids for this type... if(!ACEInstance.IsNull(IDS_ObjectTypeGUID) && ACEInstance.GetCHString(IDS_ObjectTypeGUID, chstrObjGuid)) { if(chstrObjGuid.GetLength() != 0) { try { pguidObjGuid = new GUID; } catch(...) { if(pguidObjGuid != NULL) { delete pguidObjGuid; pguidObjGuid = NULL; } } CLSIDFromString((LPWSTR)(LPCWSTR)chstrObjGuid, pguidObjGuid); } } if(!ACEInstance.IsNull(IDS_InheritedObjectGUID) && ACEInstance.GetCHString(IDS_InheritedObjectGUID, chstrInhObjGuid)) { if(chstrInhObjGuid.GetLength() != 0) { try { pguidInhObjGuid = new GUID; } catch(...) { if(pguidInhObjGuid != NULL) { delete pguidInhObjGuid; pguidInhObjGuid = NULL; } } CLSIDFromString((LPWSTR)(LPCWSTR)chstrInhObjGuid, pguidInhObjGuid); } } dacl.AddDACLEntry( sid.GetPSid(), ENUM_ACCESS_DENIED_OBJECT_ACE_TYPE, dwAccessMask, dwAceFlags, pguidObjGuid, pguidInhObjGuid); if(pguidObjGuid != NULL) delete pguidObjGuid; if(pguidInhObjGuid != NULL) delete pguidInhObjGuid; break; } case ACCESS_ALLOWED_OBJECT_ACE_TYPE: { // Need to get the guids for this type... if(!ACEInstance.IsNull(IDS_ObjectTypeGUID) && ACEInstance.GetCHString(IDS_ObjectTypeGUID, chstrObjGuid)) { if(chstrObjGuid.GetLength() != 0) { try { pguidObjGuid = new GUID; } catch(...) { if(pguidObjGuid != NULL) { delete pguidObjGuid; pguidObjGuid = NULL; } } CLSIDFromString((LPWSTR)(LPCWSTR)chstrObjGuid, pguidObjGuid); } } if(!ACEInstance.IsNull(IDS_InheritedObjectGUID) && ACEInstance.GetCHString(IDS_InheritedObjectGUID, chstrInhObjGuid)) { if(chstrInhObjGuid.GetLength() != 0) { try { pguidInhObjGuid = new GUID; } catch(...) { if(pguidInhObjGuid != NULL) { delete pguidInhObjGuid; pguidInhObjGuid = NULL; } } CLSIDFromString((LPWSTR)(LPCWSTR)chstrInhObjGuid, pguidInhObjGuid); } } dacl.AddDACLEntry( sid.GetPSid(), ENUM_ACCESS_ALLOWED_OBJECT_ACE_TYPE, dwAccessMask, dwAceFlags, pguidObjGuid, pguidInhObjGuid); if(pguidObjGuid != NULL) delete pguidObjGuid; if(pguidInhObjGuid != NULL) delete pguidInhObjGuid; break; } #endif default: { dwStatus = ERROR_INVALID_PARAMETER ; break ; } } } else { switch (dwAceType) { case ACCESS_DENIED_ACE_TYPE: { dacl.AddDACLEntry( sid.GetPSid(), ENUM_INH_ACCESS_DENIED_ACE_TYPE, dwAccessMask, dwAceFlags, NULL, NULL ); break; } case ACCESS_ALLOWED_ACE_TYPE: { dacl.AddDACLEntry( sid.GetPSid(), ENUM_INH_ACCESS_ALLOWED_ACE_TYPE, dwAccessMask, dwAceFlags, NULL, NULL ); break; } #if NTONLY >= 5 // Not yet supported under W2K //case ACCESS_ALLOWED_COMPOUND_ACE_TYPE: // { // dacl.AddDACLEntry( sid.GetPSid(), ENUM_INH_ACCESS_ALLOWED_COMPOUND_ACE_TYPE, dwAccessMask, dwAceFlags, NULL, NULL ); // break; // } case ACCESS_DENIED_OBJECT_ACE_TYPE: { // Need to get the guids for this type... if(!ACEInstance.IsNull(IDS_ObjectTypeGUID) && ACEInstance.GetCHString(IDS_ObjectTypeGUID, chstrObjGuid)) { if(chstrObjGuid.GetLength() != 0) { try { pguidObjGuid = new GUID; } catch(...) { if(pguidObjGuid != NULL) { delete pguidObjGuid; pguidObjGuid = NULL; } } CLSIDFromString((LPWSTR)(LPCWSTR)chstrObjGuid, pguidObjGuid); } } if(!ACEInstance.IsNull(IDS_InheritedObjectGUID) && ACEInstance.GetCHString(IDS_InheritedObjectGUID, chstrInhObjGuid)) { if(chstrInhObjGuid.GetLength() != 0) { try { pguidInhObjGuid = new GUID; } catch(...) { if(pguidInhObjGuid != NULL) { delete pguidInhObjGuid; pguidInhObjGuid = NULL; } } CLSIDFromString((LPWSTR)(LPCWSTR)chstrInhObjGuid, pguidInhObjGuid); } } dacl.AddDACLEntry( sid.GetPSid(), ENUM_INH_ACCESS_DENIED_OBJECT_ACE_TYPE, dwAccessMask, dwAceFlags, pguidObjGuid, pguidInhObjGuid ); if(pguidObjGuid != NULL) delete pguidObjGuid; if(pguidInhObjGuid != NULL) delete pguidInhObjGuid; break; } case ACCESS_ALLOWED_OBJECT_ACE_TYPE: { // Need to get the guids for this type... if(!ACEInstance.IsNull(IDS_ObjectTypeGUID) && ACEInstance.GetCHString(IDS_ObjectTypeGUID, chstrObjGuid)) { if(chstrObjGuid.GetLength() != 0) { try { pguidObjGuid = new GUID; } catch(...) { if(pguidObjGuid != NULL) { delete pguidObjGuid; pguidObjGuid = NULL; } } CLSIDFromString((LPWSTR)(LPCWSTR)chstrObjGuid, pguidObjGuid); } } if(!ACEInstance.IsNull(IDS_InheritedObjectGUID) && ACEInstance.GetCHString(IDS_InheritedObjectGUID, chstrInhObjGuid)) { if(chstrInhObjGuid.GetLength() != 0) { try { pguidInhObjGuid = new GUID; } catch(...) { if(pguidInhObjGuid != NULL) { delete pguidInhObjGuid; pguidInhObjGuid = NULL; } } CLSIDFromString((LPWSTR)(LPCWSTR)chstrInhObjGuid, pguidInhObjGuid); } } dacl.AddDACLEntry( sid.GetPSid(), ENUM_INH_ACCESS_ALLOWED_OBJECT_ACE_TYPE, dwAccessMask, dwAceFlags, pguidObjGuid, pguidInhObjGuid ); if(pguidObjGuid != NULL) delete pguidObjGuid; if(pguidInhObjGuid != NULL) delete pguidInhObjGuid; break; } #endif default: { dwStatus = ERROR_INVALID_PARAMETER ; break ; } } } } else { dwStatus = ERROR_INVALID_PARAMETER; } //pTrustee->Release(); // smartpointer already releases when goes out of scope } } // get Win32_Trustee object from Win32_ACE ...& decipher the ACE } } // end for loop if(lLowerBound == 0 && lUpperBound == -1L) { // DACL was EMPTY - not necessarily wrong dwStatus = STATUS_EMPTY_DACL; } } VariantClear( &vDacl ) ; } else //DACL was NULL - not nescessarily wrong. { dwStatus = STATUS_NULL_DACL ; } } return dwStatus ; } /////////////////////////////////////////////////////////////////// // // Function: FillSACLFromInstance // // Default class constructor. // // Inputs: // None. // // Outputs: // None. // // Returns: // None. // // Comments: // /////////////////////////////////////////////////////////////////// DWORD FillSACLFromInstance(CInstance *pInstance, CSACL &sacl, MethodContext *pMethodContext) { IWbemClassObjectPtr piClassObject; piClassObject.Attach(pInstance->GetClassObjectInterface()); DWORD dwStatus = ERROR_SUCCESS ; if(piClassObject) { VARIANT vSacl ; if(GetArray(piClassObject, IDS_SACL, vSacl, VT_UNKNOWN|VT_ARRAY ) ) { if( vSacl.vt != VT_NULL && vSacl.parray != NULL ) { // walk DACL LONG lDimension = 1 ; LONG lLowerBound ; SafeArrayGetLBound ( vSacl.parray , lDimension , &lLowerBound ) ; LONG lUpperBound ; SafeArrayGetUBound ( vSacl.parray , lDimension , &lUpperBound ) ; for ( LONG lIndex = lLowerBound ; lIndex <= lUpperBound ; lIndex++ ) { if( dwStatus != ERROR_SUCCESS ) { break ; } IWbemClassObjectPtr pACEObject; SafeArrayGetElement ( vSacl.parray , &lIndex , &pACEObject ) ; // take out IWbemClassObject and cast it to a Win32_ACE object. if(pACEObject) { CInstance ACEInstance(pACEObject, pMethodContext); // create an AccessEntry object from the Win32_ACE object. bool bExists =false ; VARTYPE eType ; // get Win32_Trustee object from Win32_ACE ...& decipher the ACE if ( ACEInstance.GetStatus ( IDS_Trustee, bExists , eType ) && bExists && eType == VT_UNKNOWN ) { CInstancePtr pTrustee; if ( ACEInstance.GetEmbeddedObject ( IDS_Trustee, &pTrustee, ACEInstance.GetMethodContext() ) ) { CSid sid ; if(FillSIDFromTrustee(pTrustee, sid) == ERROR_SUCCESS) { DWORD dwAceType, dwAceFlags, dwAccessMask ; CHString chstrInhObjGuid; GUID *pguidInhObjGuid = NULL; CHString chstrObjGuid; GUID *pguidObjGuid = NULL; ACEInstance.GetDWORD(IDS_AceType, dwAceType); ACEInstance.GetDWORD(IDS_AceFlags, dwAceFlags); ACEInstance.GetDWORD(IDS_AccessMask, dwAccessMask); switch(dwAceType) { case SYSTEM_AUDIT_ACE_TYPE: { sacl.AddSACLEntry( sid.GetPSid(), ENUM_SYSTEM_AUDIT_ACE_TYPE, dwAccessMask, dwAceFlags, NULL, NULL ); break; } #if NTONLY >= 5 case SYSTEM_AUDIT_OBJECT_ACE_TYPE: { // Need to get the guids for this type... if(!ACEInstance.IsNull(IDS_ObjectTypeGUID) && ACEInstance.GetCHString(IDS_ObjectTypeGUID, chstrObjGuid)) { if(chstrObjGuid.GetLength() != 0) { try { pguidObjGuid = new GUID; } catch(...) { if(pguidObjGuid != NULL) { delete pguidObjGuid; pguidObjGuid = NULL; } } CLSIDFromString((LPWSTR)(LPCWSTR)chstrObjGuid, pguidObjGuid); } } if(!ACEInstance.IsNull(IDS_InheritedObjectGUID) && ACEInstance.GetCHString(IDS_InheritedObjectGUID, chstrInhObjGuid)) { if(chstrInhObjGuid.GetLength() != 0) { try { pguidInhObjGuid = new GUID; } catch(...) { if(pguidInhObjGuid != NULL) { delete pguidInhObjGuid; pguidInhObjGuid = NULL; } } CLSIDFromString((LPWSTR)(LPCWSTR)chstrInhObjGuid, pguidInhObjGuid); } } sacl.AddSACLEntry( sid.GetPSid(), ENUM_SYSTEM_AUDIT_OBJECT_ACE_TYPE, dwAccessMask, dwAceFlags, pguidObjGuid, pguidInhObjGuid ); if(pguidObjGuid != NULL) delete pguidObjGuid; if(pguidInhObjGuid != NULL) delete pguidInhObjGuid; break; } /********************************* type not yet supported under w2k ******************************************** case SYSTEM_ALARM_ACE_TYPE: { sacl.AddSACLEntry( sid.GetPSid(), ENUM_SYSTEM_ALARM_ACE_TYPE, dwAccessMask, dwAceFlags, NULL, NULL ); break; } /********************************* type not yet supported under w2k ******************************************** /********************************* type not yet supported under w2k ******************************************** case SYSTEM_ALARM_OBJECT_ACE_TYPE: { // Need to get the guids for this type... if(!ACEInstance.IsNull(IDS_ObjectTypeGUID) && ACEInstance.GetCHString(IDS_ObjectTypeGUID, chstrObjGuid)) { if(chstrObjGuid.GetLength() != 0) { try { pguidObjGuid = new GUID; } catch(...) { if(pguidObjGuid != NULL) { delete pguidObjGuid; pguidObjGuid = NULL; } } CLSIDFromString((LPWSTR)(LPCWSTR)chstrObjGuid, pguidObjGuid); } } if(!ACEInstance.IsNull(IDS_InheritedObjectGUID) && ACEInstance.GetCHString(IDS_InheritedObjectGUID, chstrInhObjGuid)) { if(chstrInhObjGuid.GetLength() != 0) { try { pguidInhObjGuid = new GUID; } catch(...) { if(pguidInhObjGuid != NULL) { delete pguidInhObjGuid; pguidInhObjGuid = NULL; } } CLSIDFromString((LPWSTR)(LPCWSTR)chstrInhObjGuid, pguidInhObjGuid); } } sacl.AddSACLEntry( sid.GetPSid(), ENUM_SYSTEM_ALARM_OBJECT_ACE_TYPE, dwAccessMask, dwAceFlags, pguidObjGuid, pguidInhObjGuid ); if(pguidObjGuid != NULL) delete pguidObjGuid; if(pguidInhObjGuid != NULL) delete pguidInhObjGuid; break; } /********************************* type not yet supported under w2k ********************************************/ #endif default: { dwStatus = ERROR_INVALID_PARAMETER ; break; } } } else { dwStatus = ERROR_INVALID_PARAMETER; } //pTrustee->Release(); // smartpointer already releases when goes out of scope } } // get Win32_Trustee object from Win32_ACE ...& decipher the ACE } //if(pACEObject) } //for } //if(pSACL) VariantClear( &vSacl ) ; } else { dwStatus = ERROR_INVALID_PARAMETER ; } } return dwStatus ; } bool GetArray(IWbemClassObject *piClassObject, const CHString &name, VARIANT &v, VARTYPE eVariantType) { bool bRet = FALSE; VariantInit(&v); if (piClassObject) { BSTR pName = NULL; HRESULT hr; try { pName = name.AllocSysString(); hr = piClassObject->Get(pName, 0, &v, NULL, NULL); SysFreeString(pName); } catch(...) { if(pName != NULL) { SysFreeString(pName); pName = NULL; } throw; } ASSERT_BREAK((SUCCEEDED(hr)) && ((v.vt == VT_NULL) || (v.vt == eVariantType ))); if (bRet = (bool)SUCCEEDED(hr)) { if ( v.vt != VT_NULL && v.parray != NULL ) { if (v.vt == eVariantType ) { bRet = TRUE ; } else { bRet = FALSE; } } else { bRet = FALSE; } } } if (!bRet) { VariantClear(&v); } return bRet; } DWORD FillSIDFromTrustee(CInstance *pTrustee, CSid &sid) { IWbemClassObjectPtr m_piClassObject; DWORD dwStatus = ERROR_SUCCESS ; if(pTrustee) { m_piClassObject.Attach(pTrustee->GetClassObjectInterface()); VARIANT vtmp ; bool fSidObtained = false; if(GetArray(m_piClassObject,IDS_SID, vtmp, VT_UI1|VT_ARRAY ) ) { if( vtmp.vt != VT_NULL && vtmp.parray != NULL ) { if ( ::SafeArrayGetDim ( vtmp.parray ) == 1 ) { long lLowerBound , lUpperBound = 0 ; ::SafeArrayGetLBound ( vtmp.parray, 1, & lLowerBound ) ; ::SafeArrayGetUBound ( vtmp.parray, 1, & lUpperBound ) ; PSID pSid = NULL ; PVOID pTmp = NULL ; if(SUCCEEDED(::SafeArrayAccessData(vtmp.parray, &pTmp) ) ) { pSid = (PSID) malloc(lUpperBound - lLowerBound + 1) ; if(pSid) { try { memcpy(pSid,pTmp,lUpperBound - lLowerBound + 1) ; ::SafeArrayUnaccessData(vtmp.parray) ; sid = CSid(pSid); free(pSid) ; pSid = NULL; fSidObtained = true; } catch(...) { free(pSid) ; pSid = NULL; throw; } } else { dwStatus = ERROR_NOT_ENOUGH_MEMORY; } } else { dwStatus = ERROR_INVALID_PARAMETER ; } } else { dwStatus = ERROR_INVALID_PARAMETER ; } } ::VariantClear( &vtmp ) ; } if(!fSidObtained && (dwStatus == ERROR_SUCCESS)) { // If we couldn't obtain the sid from the binary // representation, try to do so from the sid string // representation (the SIDString property)... CHString chstrSIDString; if(pTrustee->GetCHString(IDS_SIDString, chstrSIDString) && chstrSIDString.GetLength() > 0) { PSID pSid = NULL; pSid = StrToSID(chstrSIDString); if(pSid) { try { sid = CSid(pSid); ::FreeSid(pSid); pSid = NULL; fSidObtained = true; } catch(...) { ::FreeSid(pSid); pSid = NULL; throw; } } else { dwStatus = ERROR_INVALID_PARAMETER; } } // If we couldn't obtain the sid from either the binary // representation or the SIDString representation, try to // do so from the Domain and Name properties (attempting // resolution on the local machine for lack of a better // choice)... if(!fSidObtained && (dwStatus == ERROR_SUCCESS)) { CHString chstrDomain, chstrName; pTrustee->GetCHString(IDS_Domain, chstrDomain); // Although we don't care whether we were able // to get the Domain above, we must at least have // a Name property specified... if(pTrustee->GetCHString(IDS_Name, chstrName) && chstrName.GetLength() > 0) { CSid csTmp(chstrDomain, chstrName, NULL); if(csTmp.IsOK() && csTmp.IsValid()) { sid = csTmp; fSidObtained = true; } } } } if(!fSidObtained && (dwStatus == ERROR_SUCCESS)) { dwStatus = ERROR_INVALID_PARAMETER ; } } else { dwStatus = ERROR_INVALID_PARAMETER; } return dwStatus ; } #ifdef NTONLY // Handy utility to dump the contents of a descriptor to // our log file. void DumpWin32Descriptor(PSECURITY_DESCRIPTOR psd, LPCWSTR wstrFilename) { CSecurityDescriptor csd(psd); csd.DumpDescriptor(); } #endif #ifdef NTONLY void Output(LPCWSTR wstrOut, LPCWSTR wstrFilename) { // Single point where we can control where output from // all security utility class Dump routines goes... if(wstrFilename == NULL) { LogMessage(wstrOut); } else { FILE *fp = NULL; if((fp = _wfopen(wstrFilename, L"at")) != NULL) { fwprintf(fp, wstrOut); fwprintf(fp,L"\r\n"); fclose(fp); } fp = NULL; } } #endif // Returns true if the user associated with the current // thread is either the owner or is a member of the group // that is the owner - e.g., it returns true if said user // has ownership of the object specified by chstrName. #ifdef NTONLY bool AmIAnOwner(const CHString &chstrName, SE_OBJECT_TYPE ObjectType) { bool fRet = false; // ALGORITHM OVERVIEW // 1) Get the sid of the user associated with the current thread. // 2) Get the owner of the object. // 3a) Compare the sid from #2 to that from #1. fRet is true if they are equal. // 3b) If not, owner's sid may be that of a group, and the user might be a // member of that group, or of a group (which would have to be a global group) // within that group. Fortunately that doesnt't recurse indefinitely, since // local groups can contain only global groups, and global groups can contain // only users (they can't be a container for other global or local groups) - see // "Windows NT Security" (Nik Okuntseff), pp. 34-35. // So here we go... // 1) Get the sid of the user associated with the current thread. Also filter out only object types we are equiped to deal with... if(ObjectType == SE_FILE_OBJECT || ObjectType == SE_LMSHARE) { CAccessRights car(true); // true tells car to use the user associated with the current thread token CSid csidCurrentUser; if(car.GetCSid(csidCurrentUser, true)) // true signals that we want car to be initialized with the domain and name looked up { // 2) Get the owner of the object. CSid csidOwner; switch(ObjectType) { case SE_FILE_OBJECT: { CSecureFile csf; if(csf.SetFileName(chstrName, FALSE) == ERROR_SUCCESS) //FALSE means we don't need the SACL { csf.GetOwner(csidOwner); } break; } case SE_LMSHARE: { CSecureShare css; if(css.SetShareName(chstrName) == ERROR_SUCCESS) { css.GetOwner(csidOwner); } break; } default: { ASSERT_BREAK(0); } } // Proceed as long as the owner sid is valid and 'ok'... if(csidOwner.IsValid() && csidOwner.IsOK()) { // 3a) Compare the sid from #2 to that from #1. fRet is true if they are equal. if(csidCurrentUser == csidOwner) { fRet = true; } else // owner might be a group... { // 3b) If not, owner's sid may be that of a group, and the user might be a // member of that group, or of a group (which would have to be a global group) // within that group. Fortunately that doesnt't recurse indefinitely, since // local groups can contain only global groups, and global groups can contain // only users (they can't be a container for other global or local groups) - see // "Windows NT Security" (Nik Okuntseff), pp. 34-35. // Since this could be a pain, call a friendly helper... SID_NAME_USE snuOwner = csidOwner.GetAccountType(); if(snuOwner == SidTypeGroup || snuOwner == SidTypeAlias || snuOwner == SidTypeWellKnownGroup) { if(IsUserInGroup(csidCurrentUser, csidOwner, snuOwner)) { fRet = true; } } } } } // we got the thread sid } // its an object we like return fRet; } #endif // Helper to determine if a particular is a member of a group, or of one of the // (global) groups that might be a member of that group. #ifdef NTONLY bool IsUserInGroup(const CSid &csidUser, const CSid &csidGroup, SID_NAME_USE snuGroup) { bool fRet = false; CNetAPI32 netapi ; if(netapi.Init() == ERROR_SUCCESS) { fRet = RecursiveFindUserInGroup(netapi, csidGroup.GetDomainName(), csidGroup.GetAccountName(), snuGroup, csidUser); } return fRet; } #endif #ifdef NTONLY bool RecursiveFindUserInGroup(CNetAPI32 &netapi, const CHString &chstrDomainName, const CHString &chstrGroupName, SID_NAME_USE snuGroup, const CSid &csidUser) { bool fRet = false; NET_API_STATUS stat; DWORD dwNumReturnedEntries = 0, dwIndex = 0, dwTotalEntries = 0; DWORD_PTR dwptrResume = NULL; // Domain Groups if (snuGroup == SidTypeGroup) { GROUP_USERS_INFO_0 *pGroupMemberData = NULL; CHString chstrDCName; if (netapi.GetDCName(chstrDomainName, chstrDCName) == ERROR_SUCCESS) { do { // Accept up to 256k worth of data. stat = netapi.NetGroupGetUsers(chstrDCName, chstrGroupName, 0, (LPBYTE *)&pGroupMemberData, 262144, &dwNumReturnedEntries, &dwTotalEntries, &dwptrResume); // If we got some data if(ERROR_SUCCESS == stat || ERROR_MORE_DATA == stat) { try { // Walk through all the returned entries... for(DWORD dwCtr = 0; dwCtr < dwNumReturnedEntries; dwCtr++) { // Get the sid type for this object... CSid sid(chstrDomainName, CHString(pGroupMemberData[dwCtr].grui0_name), NULL); if(sid == csidUser) { fRet = true; } } } catch ( ... ) { netapi.NetApiBufferFree( pGroupMemberData ); throw ; } netapi.NetApiBufferFree( pGroupMemberData ); } // IF stat OK } while ( ERROR_MORE_DATA == stat && !fRet); } // Local Groups } else if(snuGroup == SidTypeAlias || snuGroup == SidTypeWellKnownGroup) { LOCALGROUP_MEMBERS_INFO_1 *pGroupMemberData = NULL; do { // Accept up to 256k worth of data. stat = netapi.NetLocalGroupGetMembers(NULL, chstrGroupName, 1, (LPBYTE *)&pGroupMemberData, 262144, &dwNumReturnedEntries, &dwTotalEntries, &dwptrResume); // If we got some data if ( ERROR_SUCCESS == stat || ERROR_MORE_DATA == stat ) { try { // Walk through all the returned entries for(DWORD dwCtr = 0; dwCtr < dwNumReturnedEntries && !fRet; dwCtr++) { // If this is a recognized type... CSid sid(pGroupMemberData[dwCtr].lgrmi1_sid); switch(pGroupMemberData[dwCtr].lgrmi1_sidusage) { case SidTypeUser: { if(sid == csidUser) { fRet = true; } break; } case SidTypeGroup: { // If the group contained a group (would be a global group), // we need to recurse. fRet = RecursiveFindUserInGroup(netapi, sid.GetDomainName(), sid.GetAccountName(), pGroupMemberData[dwCtr].lgrmi1_sidusage, csidUser); break; } case SidTypeWellKnownGroup: { // If the group contained a group (would be a global group), // we need to recurse. fRet = RecursiveFindUserInGroup(netapi, sid.GetDomainName(), sid.GetAccountName(), pGroupMemberData[dwCtr].lgrmi1_sidusage, csidUser); break; } default: { ASSERT_BREAK(0); break; } } } } catch ( ... ) { netapi.NetApiBufferFree( pGroupMemberData ); throw ; } netapi.NetApiBufferFree( pGroupMemberData ); } // IF stat OK } while ( ERROR_MORE_DATA == stat && !fRet); } else { // Unrecognized Group type ASSERT_BREAK(0); } return fRet; } #endif