/*++ Copyright (c) 1995 Microsoft Corporation Module Name: rndsec.cpp Abstract: Security utilities for Rendezvous Control. Author: KrishnaG (from OLEDS team) Environment: User Mode - Win32 Revision History: 12-Dec-1997 DonRyan Munged KrishnaG's code to work with Rendezvous Control. --*/ /////////////////////////////////////////////////////////////////////////////// // // // Include files // // // /////////////////////////////////////////////////////////////////////////////// #define SECURITY_WIN32 //#include #include "winlocal.h" #include #include #include #include #include #include #include #include //#include "ntseapi.h" #include "rndsec.h" /////////////////////////////////////////////////////////////////////////////// //Not defined, so I pulled it from ntseapi.h /////////////////////////////////////////////////////////////////////////////// typedef struct _COMPOUND_ACCESS_ALLOWED_ACE { ACE_HEADER Header; ACCESS_MASK Mask; USHORT CompoundAceType; USHORT Reserved; ULONG SidStart; } COMPOUND_ACCESS_ALLOWED_ACE; typedef COMPOUND_ACCESS_ALLOWED_ACE *PCOMPOUND_ACCESS_ALLOWED_ACE; /////////////////////////////////////////////////////////////////////////////// // // // Private macros // // // /////////////////////////////////////////////////////////////////////////////// #define BAIL_ON_FAILURE(hr) \ if (FAILED(hr)) { goto error; } #define CONTINUE_ON_FAILURE(hr) \ if (FAILED(hr)) { continue; } /////////////////////////////////////////////////////////////////////////////// // // // Private procedures // // // /////////////////////////////////////////////////////////////////////////////// LPWSTR AllocADsStr( LPWSTR pStr ) { LPWSTR pMem; if (!pStr) return NULL; if (pMem = new WCHAR[wcslen(pStr) + 1]) wcscpy(pMem, pStr); return pMem; } HRESULT ConvertSidToString( PSID pSid, LPWSTR String ) /*++ Routine Description: This function generates a printable unicode string representation of a SID. The resulting string will take one of two forms. If the IdentifierAuthority value is not greater than 2^32, then the SID will be in the form: S-1-281736-12-72-9-110 ^ ^^ ^^ ^ ^^^ | | | | | +-----+--+-+--+---- Decimal Otherwise it will take the form: S-1-0x173495281736-12-72-9-110 ^^^^^^^^^^^^^^ ^^ ^^ ^ ^^^ Hexidecimal | | | | +--+-+--+---- Decimal Arguments: pSid - opaque pointer that supplies the SID that is to be converted to Unicode. Return Value: If the Sid is successfully converted to a Unicode string, a pointer to the Unicode string is returned, else NULL is returned. --*/ { WCHAR Buffer[256]; UCHAR i; ULONG Tmp; HRESULT hr = S_OK; SID_IDENTIFIER_AUTHORITY *pSidIdentifierAuthority; PUCHAR pSidSubAuthorityCount; if (!IsValidSid( pSid )) { *String= L'\0'; hr = HRESULT_FROM_WIN32(ERROR_INVALID_SID); return(hr); } wsprintfW(Buffer, L"S-%u-", (USHORT)(((PISID)pSid)->Revision )); wcscpy(String, Buffer); pSidIdentifierAuthority = GetSidIdentifierAuthority(pSid); if ( (pSidIdentifierAuthority->Value[0] != 0) || (pSidIdentifierAuthority->Value[1] != 0) ){ wsprintfW(Buffer, L"0x%02hx%02hx%02hx%02hx%02hx%02hx", (USHORT)pSidIdentifierAuthority->Value[0], (USHORT)pSidIdentifierAuthority->Value[1], (USHORT)pSidIdentifierAuthority->Value[2], (USHORT)pSidIdentifierAuthority->Value[3], (USHORT)pSidIdentifierAuthority->Value[4], (USHORT)pSidIdentifierAuthority->Value[5] ); wcscat(String, Buffer); } else { Tmp = (ULONG)pSidIdentifierAuthority->Value[5] + (ULONG)(pSidIdentifierAuthority->Value[4] << 8) + (ULONG)(pSidIdentifierAuthority->Value[3] << 16) + (ULONG)(pSidIdentifierAuthority->Value[2] << 24); wsprintfW(Buffer, L"%lu", Tmp); wcscat(String, Buffer); } pSidSubAuthorityCount = GetSidSubAuthorityCount(pSid); for (i=0;i< *(pSidSubAuthorityCount);i++ ) { wsprintfW(Buffer, L"-%lu", *(GetSidSubAuthority(pSid, i))); wcscat(String, Buffer); } return(S_OK); } HRESULT ConvertSidToFriendlyName( PSID pSid, LPWSTR * ppszAccountName ) { HRESULT hr = S_OK; SID_NAME_USE eUse; WCHAR szAccountName[MAX_PATH]; szAccountName[0] = L'\0'; WCHAR szDomainName[MAX_PATH]; szDomainName[0] = L'\0'; DWORD dwLen = 0; DWORD dwRet = 0; LPWSTR pszAccountName = NULL; DWORD dwAcctLen = 0; DWORD dwDomainLen = 0; dwAcctLen = sizeof(szAccountName); dwDomainLen = sizeof(szDomainName); dwRet = LookupAccountSidW( NULL, pSid, szAccountName, &dwAcctLen, szDomainName, &dwDomainLen, (PSID_NAME_USE)&eUse ); if (!dwRet) { hr = ConvertSidToString( pSid, szAccountName ); BAIL_ON_FAILURE(hr); pszAccountName = AllocADsStr(szAccountName); if (!pszAccountName) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } *ppszAccountName = pszAccountName; }else { dwLen = wcslen(szAccountName) + wcslen(szDomainName) + 1 + 1; pszAccountName = new WCHAR [dwLen]; if (!pszAccountName) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } if (szDomainName[0] && szAccountName[0]) { wsprintfW(pszAccountName,L"%s\\%s",szDomainName, szAccountName); }else if (szAccountName[0]) { wsprintfW(pszAccountName,L"%s", szAccountName); } *ppszAccountName = pszAccountName; } error: return(hr); } HRESULT ConvertAceToVariant( PBYTE pAce, LPVARIANT pvarAce ) { IADsAccessControlEntry * pAccessControlEntry = NULL; IDispatch * pDispatch = NULL; DWORD dwAceType = 0; DWORD dwAceFlags = 0; DWORD dwAccessMask = 0; LPWSTR pszAccountName = NULL; PACE_HEADER pAceHeader = NULL; LPBYTE pSidAddress = NULL; LPBYTE pOffset = NULL; DWORD dwFlags = 0; GUID ObjectGUID; GUID InheritedObjectGUID; WCHAR szObjectGUID[MAX_PATH]; WCHAR szInheritedObjectGUID[MAX_PATH]; HRESULT hr = S_OK; szObjectGUID[0] = L'\0'; szInheritedObjectGUID[0] = L'\0'; VariantInit(pvarAce); hr = CoCreateInstance( CLSID_AccessControlEntry, NULL, CLSCTX_INPROC_SERVER, IID_IADsAccessControlEntry, (void **)&pAccessControlEntry ); BAIL_ON_FAILURE(hr); pAceHeader = (ACE_HEADER *)pAce; dwAceType = pAceHeader->AceType; dwAceFlags = pAceHeader->AceFlags; dwAccessMask = *(PACCESS_MASK)((LPBYTE)pAceHeader + sizeof(ACE_HEADER)); switch (dwAceType) { case ACCESS_ALLOWED_ACE_TYPE: case ACCESS_DENIED_ACE_TYPE: case SYSTEM_AUDIT_ACE_TYPE: case SYSTEM_ALARM_ACE_TYPE: pSidAddress = (LPBYTE)pAceHeader + sizeof(ACE_HEADER) + sizeof(ACCESS_MASK); break; case ACCESS_ALLOWED_OBJECT_ACE_TYPE: case ACCESS_DENIED_OBJECT_ACE_TYPE: case SYSTEM_AUDIT_OBJECT_ACE_TYPE: case SYSTEM_ALARM_OBJECT_ACE_TYPE: pOffset = (LPBYTE)((LPBYTE)pAceHeader + sizeof(ACE_HEADER) + sizeof(ACCESS_MASK)); dwFlags = (DWORD)(*(PDWORD)pOffset); // // Now advance by the size of the flags // pOffset += sizeof(ULONG); if (dwFlags & ACE_OBJECT_TYPE_PRESENT) { memcpy(&ObjectGUID, pOffset, sizeof(GUID)); StringFromGUID2(ObjectGUID, szObjectGUID, MAX_PATH); pOffset += sizeof (GUID); } if (dwFlags & ACE_INHERITED_OBJECT_TYPE_PRESENT) { memcpy(&InheritedObjectGUID, pOffset, sizeof(GUID)); StringFromGUID2(InheritedObjectGUID, szInheritedObjectGUID, MAX_PATH); pOffset += sizeof (GUID); } pSidAddress = pOffset; break; default: BAIL_ON_FAILURE(hr); break; } hr = ConvertSidToFriendlyName( pSidAddress, &pszAccountName ); if (FAILED(hr)){ pszAccountName = AllocADsStr(L"Unknown Trustee"); } // // Now set all the information in the Access Control Entry // hr = pAccessControlEntry->put_AccessMask(dwAccessMask); hr = pAccessControlEntry->put_AceFlags(dwAceFlags); hr = pAccessControlEntry->put_AceType(dwAceType); // // Extended ACE information // hr = pAccessControlEntry->put_Flags(dwFlags); if (dwFlags & ACE_OBJECT_TYPE_PRESENT) { // // Add in the Object Type GUID // hr = pAccessControlEntry->put_ObjectType(szObjectGUID); } if (dwFlags & ACE_INHERITED_OBJECT_TYPE_PRESENT) { // // Add in the Inherited Object Type GUID // hr = pAccessControlEntry->put_InheritedObjectType(szInheritedObjectGUID); } hr = pAccessControlEntry->put_Trustee(pszAccountName); hr = pAccessControlEntry->QueryInterface( IID_IDispatch, (void **)&pDispatch ); BAIL_ON_FAILURE(hr); V_DISPATCH(pvarAce) = pDispatch; V_VT(pvarAce) = VT_DISPATCH; cleanup: if (pszAccountName) { delete (pszAccountName); } if (pAccessControlEntry) { pAccessControlEntry->Release(); } return(hr); error: if (pDispatch) { pDispatch->Release(); } goto cleanup; } HRESULT ConvertACLToVariant( PACL pACL, LPVARIANT pvarACL ) { IADsAccessControlList * pAccessControlList = NULL; IDispatch * pDispatch = NULL; VARIANT varAce; DWORD dwAclSize = 0; DWORD dwAclRevision = 0; DWORD dwAceCount = 0; ACL_SIZE_INFORMATION AclSize; ACL_REVISION_INFORMATION AclRevision; DWORD dwStatus = 0; DWORD i = 0; DWORD dwNewAceCount = 0; HRESULT hr = S_OK; LPBYTE pAceAddress = NULL; memset(&AclSize, 0, sizeof(ACL_SIZE_INFORMATION)); memset(&AclRevision, 0, sizeof(ACL_REVISION_INFORMATION)); dwStatus = GetAclInformation( pACL, &AclSize, sizeof(ACL_SIZE_INFORMATION), AclSizeInformation ); dwStatus = GetAclInformation( pACL, &AclRevision, sizeof(ACL_REVISION_INFORMATION), AclRevisionInformation ); dwAceCount = AclSize.AceCount; dwAclRevision = AclRevision.AclRevision; VariantInit(pvarACL); hr = CoCreateInstance( CLSID_AccessControlList, NULL, CLSCTX_INPROC_SERVER, IID_IADsAccessControlList, (void **)&pAccessControlList ); BAIL_ON_FAILURE(hr); for (i = 0; i < dwAceCount; i++) { dwStatus = GetAce(pACL, i, (void **)&pAceAddress); hr = ConvertAceToVariant( pAceAddress, (LPVARIANT)&varAce ); hr = pAccessControlList->AddAce(V_DISPATCH(&varAce)); if (SUCCEEDED(hr)) { dwNewAceCount++; } VariantClear(&varAce); } pAccessControlList->put_AclRevision(dwAclRevision); pAccessControlList->put_AceCount(dwNewAceCount); hr = pAccessControlList->QueryInterface( IID_IDispatch, (void **)&pDispatch ); V_VT(pvarACL) = VT_DISPATCH; V_DISPATCH(pvarACL) = pDispatch; error: if (pAccessControlList) { pAccessControlList->Release(); } return(hr); } HRESULT SecCreateSidFromArray ( OUT PSID *PPSid, IN PSID_IDENTIFIER_AUTHORITY PSidAuthority, IN UCHAR SubAuthorityCount, IN ULONG SubAuthorities[], OUT PDWORD pdwSidSize ) /*++ Routine Description: Creates a SID with desired authority and sub authorities. NOTE: This routine allocates memory for the SID. When finished the caller should free memory using SEC_FREE (PSid). Arguments: PPSid -- addr of ptr to SID to be created Note: if SID creation fails ptr set to NULL PSidAuthority -- desired value for SID authority SubAuthorityCount -- number of sub authorities desired SubAuthorities -- sub-authority values, MUST SPECIFY contain at least SubAuthorityCount number of values Return Value: STATUS_SUCCESS if SID created. STATUS_UNSUCCESSFUL otherwise. --*/ { USHORT iSub; /* sub-authority index */ DWORD dwSidSize = 0; HRESULT hr = S_OK; /* allocate memory for SID */ dwSidSize = GetSidLengthRequired(SubAuthorityCount); *PPSid = (PSID) new BYTE[dwSidSize]; if (! *PPSid){ hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } *pdwSidSize = dwSidSize; /* initialize SID with top level SID identifier authority */ InitializeSid( *PPSid, PSidAuthority, SubAuthorityCount); /* fill in sub authorities */ for (iSub=0; iSub < SubAuthorityCount; iSub++) * GetSidSubAuthority( *PPSid, iSub) = SubAuthorities[iSub]; /* sanity check */ if ( ! IsValidSid( *PPSid) ) { delete (*PPSid); *PPSid = NULL; hr = HRESULT_FROM_WIN32(ERROR_INVALID_SID); BAIL_ON_FAILURE(hr); } error: return(hr); } HRESULT ConvertStringToSid( IN PWSTR string, OUT PSID *sid, OUT PDWORD pdwSidSize, OUT PWSTR *end ) { HRESULT hr = S_OK; UCHAR revision; UCHAR sub_authority_count; SID_IDENTIFIER_AUTHORITY authority; ULONG sub_authority[SID_MAX_SUB_AUTHORITIES]; PWSTR end_list; PWSTR current; PWSTR next; ULONG x; *sid = NULL; if (((*string != L'S') && (*string != L's')) || (*(string + 1) != L'-')) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_SID); BAIL_ON_FAILURE(hr); } current = string + 2; revision = (UCHAR)wcstol(current, &end_list, 10); current = end_list + 1; // // Count the number of characters in the indentifer authority... // next = wcschr(current, L'-'); if((next != NULL) && (next - current == 6)) { for(x = 0; x < 6; x++) { authority.Value[x] = (UCHAR)next[x]; } current +=6; } else { ULONG Auto = wcstoul(current, &end_list, 10); authority.Value[0] = authority.Value[1] = 0; authority.Value[5] = (UCHAR)Auto & 0xF; authority.Value[4] = (UCHAR)((Auto >> 8) & 0xFF); authority.Value[3] = (UCHAR)((Auto >> 16) & 0xFF); authority.Value[2] = (UCHAR)((Auto >> 24) & 0xFF); current = end_list; } // // Now, count the number of sub auths // sub_authority_count = 0; next = current; // // We'll have to count our sub authoritys one character at a time, // since there are several deliminators that we can have... // while(next) { next++; if(*next == L'-') { // // We've found one! // sub_authority_count++; } else if(*next == L';' || *next == L'\0') { *end = next; sub_authority_count++; break; } } if(sub_authority_count != 0) { current++; for(x = 0; x < sub_authority_count; x++) { sub_authority[x] = wcstoul(current, &end_list, 10); current = end_list + 1; } } // // Now, create the SID // hr = SecCreateSidFromArray( sid, &authority, sub_authority_count, sub_authority, pdwSidSize ); if (SUCCEEDED(hr)) { /* Set the revision to what was specified in the string, in case, our system creates one with newer revision */ ((SID *)(*sid))->Revision = revision; } error: return(hr); } HRESULT ConvertTrusteeToSid( BSTR bstrTrustee, PSID * ppSid, PDWORD pdwSidSize ) { HRESULT hr = S_OK; BYTE Sid[MAX_PATH]; DWORD dwSidSize = sizeof(Sid); DWORD dwRet = 0; WCHAR szDomainName[MAX_PATH]; DWORD dwDomainSize = sizeof(szDomainName)/sizeof(WCHAR); SID_NAME_USE eUse; PSID pSid = NULL; LPWSTR pszEnd = NULL; BOOL fNTDSType = FALSE; dwSidSize = sizeof(Sid); dwRet = LookupAccountNameW( NULL, bstrTrustee, Sid, &dwSidSize, szDomainName, &dwDomainSize, (PSID_NAME_USE)&eUse ); if (!dwRet) { hr = HRESULT_FROM_WIN32(GetLastError()); } // // If neither the NTDS nor the U2 conversion // worked, then try a textual translation // if (FAILED(hr)) { hr = ConvertStringToSid( bstrTrustee, &pSid, &dwSidSize, &pszEnd ); BAIL_ON_FAILURE(hr); memcpy(Sid,pSid, dwSidSize); if (pSid) { delete pSid; } } pSid = (PSID) new BYTE[dwSidSize]; if (!pSid) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } memcpy(pSid, Sid, dwSidSize); *pdwSidSize = dwSidSize; *ppSid = pSid; error: return(hr); } HRESULT GetOwnerSecurityIdentifier( IADsSecurityDescriptor FAR * pSecDes, PSID * ppSid, PBOOL pfOwnerDefaulted ) { BSTR bstrOwner = NULL; DWORD dwSidSize = 0; HRESULT hr = S_OK; VARIANT_BOOL varBool = VARIANT_FALSE; hr = pSecDes->get_Owner( &bstrOwner ); BAIL_ON_FAILURE(hr); hr = pSecDes->get_OwnerDefaulted( &varBool ); BAIL_ON_FAILURE(hr); if (varBool == VARIANT_FALSE) { if (bstrOwner && *bstrOwner) { hr = ConvertTrusteeToSid( bstrOwner, ppSid, &dwSidSize ); BAIL_ON_FAILURE(hr); *pfOwnerDefaulted = FALSE; }else { *ppSid = NULL; *pfOwnerDefaulted = FALSE; } }else { *ppSid = NULL; dwSidSize = 0; *pfOwnerDefaulted = TRUE; } error: if (bstrOwner) { SysFreeString(bstrOwner); } return(hr); } HRESULT ComputeTotalAclSize( PACE_HEADER * ppAceHdr, DWORD dwAceCount, PDWORD pdwAclSize ) { DWORD i = 0; PACE_HEADER pAceHdr = NULL; DWORD dwAceSize = 0; DWORD dwAclSize = 0; for (i = 0; i < dwAceCount; i++) { pAceHdr = *(ppAceHdr + i); dwAceSize = pAceHdr->AceSize; dwAclSize += dwAceSize; } dwAclSize += sizeof(ACL); *pdwAclSize = dwAclSize; return(S_OK); } HRESULT ConvertAccessControlEntryToAce( IADsAccessControlEntry * pAccessControlEntry, LPBYTE * ppAce ) { DWORD dwAceType = 0; HRESULT hr = S_OK; BSTR bstrTrustee = NULL; PSID pSid = NULL; DWORD dwSidSize = 0; DWORD dwAceFlags = 0; DWORD dwAccessMask = 0; DWORD dwAceSize = 0; LPBYTE pAce = NULL; PACCESS_MASK pAccessMask = NULL; PSID pSidAddress = NULL; PUSHORT pCompoundAceType = NULL; DWORD dwCompoundAceType = 0; PACE_HEADER pAceHeader = NULL; LPBYTE pOffset = NULL; BSTR bstrObjectTypeClsid = NULL; BSTR bstrInheritedObjectTypeClsid = NULL; GUID ObjectTypeGUID; GUID InheritedObjectTypeGUID; PULONG pFlags; DWORD dwFlags = 0; hr = pAccessControlEntry->get_AceType((LONG *)&dwAceType); BAIL_ON_FAILURE(hr); hr = pAccessControlEntry->get_Trustee(&bstrTrustee); BAIL_ON_FAILURE(hr); hr = ConvertTrusteeToSid( bstrTrustee, &pSid, &dwSidSize ); BAIL_ON_FAILURE(hr); hr = pAccessControlEntry->get_AceFlags((long *)&dwAceFlags); BAIL_ON_FAILURE(hr); hr = pAccessControlEntry->get_AccessMask((long *)&dwAccessMask); BAIL_ON_FAILURE(hr); // // we will compensateby adding the entire ACE size // dwAceSize = dwSidSize - sizeof(ULONG); switch (dwAceType) { case ACCESS_ALLOWED_ACE_TYPE: dwAceSize += sizeof(ACCESS_ALLOWED_ACE); pAce = new BYTE[dwAceSize]; if (!pAce) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } pAceHeader = (PACE_HEADER)pAce; pAceHeader->AceType = (UCHAR)dwAceType; pAceHeader->AceFlags = (UCHAR)dwAceFlags; pAceHeader->AceSize = (USHORT)dwAceSize; pAccessMask = (PACCESS_MASK)((LPBYTE)pAceHeader + sizeof(ACE_HEADER)); *pAccessMask = (ACCESS_MASK)dwAccessMask; pSidAddress = (PSID)((LPBYTE)pAccessMask + sizeof(ACCESS_MASK)); memcpy(pSidAddress, pSid, dwSidSize); break; case ACCESS_DENIED_ACE_TYPE: dwAceSize += sizeof(ACCESS_ALLOWED_ACE); pAce = new BYTE[dwAceSize]; if (!pAce) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } pAceHeader = (PACE_HEADER)pAce; pAceHeader->AceType = (UCHAR)dwAceType; pAceHeader->AceFlags = (UCHAR)dwAceFlags; pAceHeader->AceSize = (USHORT)dwAceSize; pAccessMask = (PACCESS_MASK)((LPBYTE)pAceHeader + sizeof(ACE_HEADER)); *pAccessMask = (ACCESS_MASK)dwAccessMask; pSidAddress = (PSID)((LPBYTE)pAccessMask + sizeof(ACCESS_MASK)); memcpy(pSidAddress, pSid, dwSidSize); break; case SYSTEM_AUDIT_ACE_TYPE: dwAceSize += sizeof(ACCESS_ALLOWED_ACE); pAce = new BYTE[dwAceSize]; if (!pAce) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } pAceHeader = (PACE_HEADER)pAce; pAceHeader->AceType = (UCHAR)dwAceType; pAceHeader->AceFlags = (UCHAR)dwAceFlags; pAceHeader->AceSize = (USHORT)dwAceSize; pAccessMask = (PACCESS_MASK)((LPBYTE)pAceHeader + sizeof(ACE_HEADER)); *pAccessMask = (ACCESS_MASK)dwAccessMask; pSidAddress = (PSID)((LPBYTE)pAccessMask + sizeof(ACCESS_MASK)); memcpy(pSidAddress, pSid, dwSidSize); break; case SYSTEM_ALARM_ACE_TYPE: dwAceSize += sizeof(ACCESS_ALLOWED_ACE); pAce = new BYTE[dwAceSize]; if (!pAce) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } pAceHeader = (PACE_HEADER)pAce; pAceHeader->AceType = (UCHAR)dwAceType; pAceHeader->AceFlags = (UCHAR)dwAceFlags; pAceHeader->AceSize = (USHORT)dwAceSize; pAccessMask = (PACCESS_MASK)((LPBYTE)pAceHeader + sizeof(ACE_HEADER)); *pAccessMask = (ACCESS_MASK)dwAccessMask; pSidAddress = (PSID)((LPBYTE)pAccessMask + sizeof(ACCESS_MASK)); memcpy(pSidAddress, pSid, dwSidSize); break; case ACCESS_ALLOWED_COMPOUND_ACE_TYPE: dwAceSize += sizeof(COMPOUND_ACCESS_ALLOWED_ACE); pAce = new BYTE[dwAceSize]; if (!pAce) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } pAceHeader = (PACE_HEADER)pAce; pAceHeader->AceType = (UCHAR)dwAceType; pAceHeader->AceFlags = (UCHAR)dwAceFlags; pAceHeader->AceSize = (USHORT)dwAceSize; pAccessMask = (PACCESS_MASK)((LPBYTE)pAceHeader + sizeof(ACE_HEADER)); *pAccessMask = (ACCESS_MASK)dwAccessMask; pCompoundAceType = (PUSHORT)(pAccessMask + sizeof(ACCESS_MASK)); *pCompoundAceType = (USHORT)dwCompoundAceType; // // Fill in the reserved field here. // pSidAddress = (PSID)((LPBYTE)pCompoundAceType + sizeof(DWORD)); memcpy(pSidAddress, pSid, dwSidSize); break; case ACCESS_ALLOWED_OBJECT_ACE_TYPE: case ACCESS_DENIED_OBJECT_ACE_TYPE: case SYSTEM_AUDIT_OBJECT_ACE_TYPE: case SYSTEM_ALARM_OBJECT_ACE_TYPE: hr = pAccessControlEntry->get_AceFlags((LONG *)&dwAceFlags); BAIL_ON_FAILURE(hr); hr = pAccessControlEntry->get_Flags((LONG *)&dwFlags); BAIL_ON_FAILURE(hr); if (dwFlags & ACE_OBJECT_TYPE_PRESENT) { dwAceSize += sizeof(GUID); } if (dwFlags & ACE_INHERITED_OBJECT_TYPE_PRESENT) { dwAceSize += sizeof(GUID); } hr = pAccessControlEntry->get_ObjectType(&bstrObjectTypeClsid); BAIL_ON_FAILURE(hr); hr = CLSIDFromString(bstrObjectTypeClsid, &ObjectTypeGUID); BAIL_ON_FAILURE(hr); hr = pAccessControlEntry->get_InheritedObjectType(&bstrInheritedObjectTypeClsid); BAIL_ON_FAILURE(hr); hr = CLSIDFromString(bstrInheritedObjectTypeClsid, &InheritedObjectTypeGUID); BAIL_ON_FAILURE(hr); dwAceSize += sizeof(ACCESS_ALLOWED_OBJECT_ACE); pAce = new BYTE[dwAceSize]; if (!pAce) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } pAceHeader = (PACE_HEADER)pAce; pAceHeader->AceType = (UCHAR)dwAceType; pAceHeader->AceFlags = (UCHAR)dwAceFlags; pAceHeader->AceSize = (USHORT)dwAceSize; pAccessMask = (PACCESS_MASK)((LPBYTE)pAceHeader + sizeof(ACE_HEADER)); *pAccessMask = (ACCESS_MASK)dwAccessMask; // // Fill in Flags // pOffset = (LPBYTE)((LPBYTE)pAceHeader + sizeof(ACE_HEADER) + sizeof(ACCESS_MASK)); pFlags = (PULONG)(pOffset); *pFlags = dwFlags; pOffset += sizeof(ULONG); if (dwFlags & ACE_OBJECT_TYPE_PRESENT) { memcpy(pOffset, &ObjectTypeGUID, sizeof(GUID)); pOffset += sizeof(GUID); } if (dwFlags & ACE_INHERITED_OBJECT_TYPE_PRESENT) { memcpy(pOffset, &InheritedObjectTypeGUID, sizeof(GUID)); pOffset += sizeof(GUID); } pSidAddress = (PSID)((LPBYTE)pOffset); memcpy(pSidAddress, pSid, dwSidSize); break; } *ppAce = pAce; error: if (bstrTrustee) { SysFreeString(bstrTrustee); } if (pSid) { delete (pSid); } return(hr); } HRESULT ConvertAccessControlListToAcl( IADsAccessControlList FAR * pAccessList, PACL * ppAcl ) { IUnknown * pUnknown = NULL; IEnumVARIANT * pEnumerator = NULL; HRESULT hr = S_OK; DWORD i = 0; DWORD cReturned = 0; VARIANT varAce; DWORD dwAceCount = 0; IADsAccessControlEntry FAR * pAccessControlEntry = NULL; LPBYTE pTempAce = NULL; DWORD dwCount = 0; PACL pAcl = NULL; DWORD dwAclSize = 0; PACE_HEADER * ppAceHdr = NULL; DWORD dwRet = 0; DWORD dwAclRevision = 0; DWORD dwStatus = 0; DWORD dwError = 0; hr = pAccessList->get_AceCount((long *)&dwAceCount); BAIL_ON_FAILURE(hr); hr = pAccessList->get__NewEnum( &pUnknown ); BAIL_ON_FAILURE(hr); hr = pUnknown->QueryInterface( IID_IEnumVARIANT, (void FAR * FAR *)&pEnumerator ); BAIL_ON_FAILURE(hr); ppAceHdr = new PACE_HEADER [dwAceCount]; if (!ppAceHdr) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } for (i = 0; i < dwAceCount; i++) { VariantInit(&varAce); hr = pEnumerator->Next( 1, &varAce, &cReturned ); CONTINUE_ON_FAILURE(hr); hr = (V_DISPATCH(&varAce))->QueryInterface( IID_IADsAccessControlEntry, (void **)&pAccessControlEntry ); CONTINUE_ON_FAILURE(hr); hr = ConvertAccessControlEntryToAce( pAccessControlEntry, &(pTempAce) ); // ZoltanS: Rather than CONTINUE_ON_FAILURE, let's bail so that we // know if the Ace we set is invalid. BAIL_ON_FAILURE(hr); *(ppAceHdr + dwCount) = (PACE_HEADER)pTempAce; VariantClear(&varAce); if (pAccessControlEntry) { pAccessControlEntry->Release(); pAccessControlEntry = NULL; } dwCount++; } hr = ComputeTotalAclSize(ppAceHdr, dwCount, &dwAclSize); BAIL_ON_FAILURE(hr); pAcl = (PACL)new BYTE[dwAclSize]; if (!pAcl) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } hr = pAccessList->get_AclRevision((long *)&dwAclRevision); BAIL_ON_FAILURE(hr); dwRet = InitializeAcl( pAcl, dwAclSize, dwAclRevision ); if (!dwRet) { hr = HRESULT_FROM_WIN32(GetLastError()); BAIL_ON_FAILURE(hr); } for (i = 0; i < dwCount; i++) { dwStatus = AddAce( pAcl, dwAclRevision, i, (LPBYTE)*(ppAceHdr + i), (*(ppAceHdr + i))->AceSize ); if (!dwStatus) { dwError = GetLastError(); } } *ppAcl = pAcl; error: if (ppAceHdr) { for (i = 0; i < dwCount; i++) { if (*(ppAceHdr + i)) { delete (*(ppAceHdr + i)); } } delete (ppAceHdr); } if (pUnknown) { pUnknown->Release(); } if (pEnumerator) { pEnumerator->Release(); } return(hr); } HRESULT GetGroupSecurityIdentifier( IADsSecurityDescriptor FAR * pSecDes, PSID * ppSid, PBOOL pfGroupDefaulted ) { BSTR bstrGroup = NULL; DWORD dwSidSize = 0; HRESULT hr = S_OK; VARIANT_BOOL varBool = VARIANT_FALSE; hr = pSecDes->get_Group( &bstrGroup ); BAIL_ON_FAILURE(hr); hr = pSecDes->get_GroupDefaulted( &varBool ); BAIL_ON_FAILURE(hr); if (varBool == VARIANT_FALSE) { if (bstrGroup && *bstrGroup) { hr = ConvertTrusteeToSid( bstrGroup, ppSid, &dwSidSize ); BAIL_ON_FAILURE(hr); *pfGroupDefaulted = FALSE; }else { *ppSid = NULL; *pfGroupDefaulted = FALSE; } }else { *ppSid = NULL; dwSidSize = 0; *pfGroupDefaulted = TRUE; } error: if (bstrGroup) { SysFreeString(bstrGroup); } return(hr); } HRESULT GetDacl( IADsSecurityDescriptor FAR * pSecDes, PACL * ppDacl, PBOOL pfDaclDefaulted ) { IADsAccessControlList FAR * pDiscAcl = NULL; IDispatch FAR * pDispatch = NULL; HRESULT hr = S_OK; VARIANT_BOOL varBool = VARIANT_FALSE; hr = pSecDes->get_DaclDefaulted( &varBool ); BAIL_ON_FAILURE(hr); if (varBool == VARIANT_FALSE) { *pfDaclDefaulted = FALSE; }else { *pfDaclDefaulted = TRUE; } hr = pSecDes->get_DiscretionaryAcl( &pDispatch ); BAIL_ON_FAILURE(hr); if (!pDispatch) { *ppDacl = NULL; goto error; } hr = pDispatch->QueryInterface( IID_IADsAccessControlList, (void **)&pDiscAcl ); BAIL_ON_FAILURE(hr); hr = ConvertAccessControlListToAcl( pDiscAcl, ppDacl ); BAIL_ON_FAILURE(hr); error: if (pDispatch) { pDispatch->Release(); } if (pDiscAcl) { pDiscAcl->Release(); } return(hr); } HRESULT GetSacl( IADsSecurityDescriptor FAR * pSecDes, PACL * ppSacl, PBOOL pfSaclDefaulted ) { IADsAccessControlList FAR * pSystemAcl = NULL; IDispatch FAR * pDispatch = NULL; HRESULT hr = S_OK; VARIANT_BOOL varBool = VARIANT_FALSE; hr = pSecDes->get_SaclDefaulted( &varBool ); BAIL_ON_FAILURE(hr); if (varBool == VARIANT_FALSE) { *pfSaclDefaulted = FALSE; }else { *pfSaclDefaulted = TRUE; } hr = pSecDes->get_SystemAcl( &pDispatch ); BAIL_ON_FAILURE(hr); if (!pDispatch) { *ppSacl = NULL; goto error; } hr = pDispatch->QueryInterface( IID_IADsAccessControlList, (void **)&pSystemAcl ); BAIL_ON_FAILURE(hr); hr = ConvertAccessControlListToAcl( pSystemAcl, ppSacl ); BAIL_ON_FAILURE(hr); error: if (pDispatch) { pDispatch->Release(); } if (pSystemAcl) { pSystemAcl->Release(); } return(hr); } /////////////////////////////////////////////////////////////////////////////// // // // Public procedures // // // /////////////////////////////////////////////////////////////////////////////// HRESULT ConvertSDToIDispatch( IN PSECURITY_DESCRIPTOR pSecurityDescriptor, OUT IDispatch ** ppIDispatch ) { IADsSecurityDescriptor * pSecDes = NULL; IDispatch * pDispatch = NULL; LPWSTR pszGroup = NULL; LPWSTR pszOwner = NULL; BOOL fOwnerDefaulted = 0; BOOL fGroupDefaulted = 0; BOOL fDaclDefaulted = 0; BOOL fSaclDefaulted = 0; BOOL fSaclPresent = 0; BOOL fDaclPresent = 0; LPBYTE pOwnerSidAddress = NULL; LPBYTE pGroupSidAddress = NULL; LPBYTE pDACLAddress = NULL; LPBYTE pSACLAddress = NULL; DWORD dwRet = 0; VARIANT varDACL; VARIANT varSACL; HRESULT hr = S_OK; DWORD dwRevision = 0; WORD wControl = 0; memset(&varSACL, 0, sizeof(VARIANT)); memset(&varDACL, 0, sizeof(VARIANT)); if (!pSecurityDescriptor) { return(E_FAIL); } dwRet = GetSecurityDescriptorControl( pSecurityDescriptor, &wControl, &dwRevision ); if (!dwRet){ hr = HRESULT_FROM_WIN32(GetLastError()); BAIL_ON_FAILURE(hr); } dwRet = GetSecurityDescriptorOwner( pSecurityDescriptor, (PSID *)&pOwnerSidAddress, &fOwnerDefaulted ); if (!dwRet){ hr = HRESULT_FROM_WIN32(GetLastError()); BAIL_ON_FAILURE(hr); } hr = ConvertSidToFriendlyName( pOwnerSidAddress, &pszOwner ); BAIL_ON_FAILURE(hr); dwRet = GetSecurityDescriptorGroup( pSecurityDescriptor, (PSID *)&pGroupSidAddress, &fOwnerDefaulted ); if (!dwRet){ hr = HRESULT_FROM_WIN32(GetLastError()); BAIL_ON_FAILURE(hr); } hr = ConvertSidToFriendlyName( pGroupSidAddress, &pszGroup ); BAIL_ON_FAILURE(hr); dwRet = GetSecurityDescriptorDacl( pSecurityDescriptor, &fDaclPresent, (PACL*)&pDACLAddress, &fDaclDefaulted ); if (pDACLAddress) { hr = ConvertACLToVariant( (PACL)pDACLAddress, &varDACL ); BAIL_ON_FAILURE(hr); } dwRet = GetSecurityDescriptorSacl( pSecurityDescriptor, &fSaclPresent, (PACL *)&pSACLAddress, &fSaclDefaulted ); if (!dwRet){ hr = HRESULT_FROM_WIN32(GetLastError()); BAIL_ON_FAILURE(hr); } if (pSACLAddress) { hr = ConvertACLToVariant( (PACL)pSACLAddress, &varSACL ); BAIL_ON_FAILURE(hr); } hr = CoCreateInstance( CLSID_SecurityDescriptor, NULL, CLSCTX_INPROC_SERVER, IID_IADsSecurityDescriptor, (void **)&pSecDes ); BAIL_ON_FAILURE(hr); if ( pszOwner ) hr = pSecDes->put_Owner(pszOwner); BAIL_ON_FAILURE(hr); if ( pszGroup ) hr = pSecDes->put_Group(pszGroup); BAIL_ON_FAILURE(hr); hr = pSecDes->put_Revision(dwRevision); BAIL_ON_FAILURE(hr); hr = pSecDes->put_Control((DWORD)wControl); BAIL_ON_FAILURE(hr); hr = pSecDes->put_DiscretionaryAcl(V_DISPATCH(&varDACL)); BAIL_ON_FAILURE(hr); hr = pSecDes->put_SystemAcl(V_DISPATCH(&varSACL)); BAIL_ON_FAILURE(hr); hr = pSecDes->QueryInterface(IID_IDispatch, (void**)&pDispatch); BAIL_ON_FAILURE(hr); *ppIDispatch = pDispatch; error: VariantClear(&varSACL); VariantClear(&varDACL); if (pszOwner) { delete (pszOwner); } if (pszGroup) { delete (pszGroup); } if (pSecDes) { pSecDes->Release(); } return(hr); } HRESULT ConvertSDToVariant( IN PSECURITY_DESCRIPTOR pSecurityDescriptor, OUT VARIANT * pVarSec ) { IDispatch *pIDispatch; HRESULT hr = ConvertSDToIDispatch(pSecurityDescriptor, &pIDispatch); if (FAILED(hr)) { return hr; } VariantInit(pVarSec); V_VT(pVarSec) = VT_DISPATCH; V_DISPATCH(pVarSec) = pIDispatch; return S_OK; } HRESULT ConvertObjectToSD( IN IADsSecurityDescriptor FAR * pSecDes, OUT PSECURITY_DESCRIPTOR * ppSecurityDescriptor, OUT PDWORD pdwSDLength ) { HRESULT hr = S_OK; SECURITY_DESCRIPTOR AbsoluteSD; PSECURITY_DESCRIPTOR pRelative = NULL; BOOL Defaulted = FALSE; BOOL DaclPresent = FALSE; BOOL SaclPresent = FALSE; BOOL fDaclDefaulted = FALSE; BOOL fSaclDefaulted = FALSE; BOOL fOwnerDefaulted = FALSE; BOOL fGroupDefaulted = FALSE; PSID pOwnerSid = NULL; PSID pGroupSid = NULL; PACL pDacl = NULL; PACL pSacl = NULL; DWORD dwSDLength = 0; DWORD dwRet = 0; BOOL dwStatus = 0; // // Initialize *pSizeSD = 0; // dwRet = InitializeSecurityDescriptor ( &AbsoluteSD, SECURITY_DESCRIPTOR_REVISION1 ); if (!dwRet) { hr = E_FAIL; BAIL_ON_FAILURE(hr); } hr = GetOwnerSecurityIdentifier( pSecDes, &pOwnerSid, &fOwnerDefaulted ); BAIL_ON_FAILURE(hr); dwStatus = SetSecurityDescriptorOwner( &AbsoluteSD, pOwnerSid, fOwnerDefaulted ); if (!dwStatus) { hr = HRESULT_FROM_WIN32(GetLastError()); BAIL_ON_FAILURE(hr); } hr = GetGroupSecurityIdentifier( pSecDes, &pGroupSid, &fGroupDefaulted ); BAIL_ON_FAILURE(hr); dwStatus = SetSecurityDescriptorGroup( &AbsoluteSD, pGroupSid, fGroupDefaulted ); if (!dwStatus) { hr = HRESULT_FROM_WIN32(GetLastError()); BAIL_ON_FAILURE(hr); } hr = GetDacl( pSecDes, &pDacl, &fDaclDefaulted ); BAIL_ON_FAILURE(hr); if (pDacl || fDaclDefaulted) { DaclPresent = TRUE; } dwStatus = SetSecurityDescriptorDacl( &AbsoluteSD, DaclPresent, pDacl, fDaclDefaulted ); if (!dwStatus) { hr = HRESULT_FROM_WIN32(GetLastError()); BAIL_ON_FAILURE(hr); } hr = GetSacl( pSecDes, &pSacl, &fSaclDefaulted ); BAIL_ON_FAILURE(hr); if (pSacl || fSaclDefaulted) { SaclPresent = TRUE; } dwStatus = SetSecurityDescriptorSacl( &AbsoluteSD, SaclPresent, pSacl, fSaclDefaulted ); if (!dwStatus) { hr = HRESULT_FROM_WIN32(GetLastError()); BAIL_ON_FAILURE(hr); } dwSDLength = GetSecurityDescriptorLength( &AbsoluteSD ); pRelative = LocalAlloc(LPTR, dwSDLength); if (!pRelative) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } if (!MakeSelfRelativeSD (&AbsoluteSD, pRelative, &dwSDLength)) { delete (pRelative); hr = HRESULT_FROM_WIN32(GetLastError()); BAIL_ON_FAILURE(hr); } *ppSecurityDescriptor = pRelative; *pdwSDLength = dwSDLength; cleanup: if (pDacl) { delete (pDacl); } if (pSacl) { delete (pSacl); } if (pOwnerSid) { delete (pOwnerSid); } if (pGroupSid) { delete (pGroupSid); } return(hr); error: if (pRelative) { LocalFree( pRelative ); } *ppSecurityDescriptor = NULL; *pdwSDLength = 0; goto cleanup; } HRESULT ConvertObjectToSDDispatch( IN IDispatch * pDisp, OUT PSECURITY_DESCRIPTOR * ppSecurityDescriptor, OUT PDWORD pdwSDLength ) { HRESULT hr; IADsSecurityDescriptor * pSecDes; hr = pDisp->QueryInterface( IID_IADsSecurityDescriptor, (VOID **)&pSecDes ); if (FAILED(hr)) { return hr; } hr = ConvertObjectToSD(pSecDes, ppSecurityDescriptor, pdwSDLength); return hr; }