//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1995. // // File: libmain.cxx // // Contents: LibMain for nds.dll // // Functions: LibMain, DllGetClassObject // // History: 25-Oct-94 KrishnaG Created. // //---------------------------------------------------------------------------- #include "oleds.hxx" #pragma hdrstop #define GetAce ADSIGetAce #define DeleteAce ADSIDeleteAce #define GetAclInformation ADSIGetAclInformation #define SetAclInformation ADSISetAclInformation #define IsValidAcl ADSIIsValidAcl #define InitializeAcl ADSIInitializeAcl extern HRESULT ConvertSidToString( PSID pSid, LPWSTR String ); DWORD GetDomainDNSNameForDomain( LPWSTR pszDomainFlatName, BOOL fVerify, BOOL fWriteable, LPWSTR pszServerName, LPWSTR pszDomainDNSName ); // // Helper routine. // PSID ComputeSidFromAceAddress( LPBYTE pAce ); //+--------------------------------------------------------------------------- // Function: GetLsaPolicyHandle - helper routine. // // Synopsis: Returns the lsa policy handle to the server in question. // If a serverName is present we will first try that. If no servername // is present we will try and connect up to the default server for the // currently logged on user. If everything else fails, we will // connnect to the local machine (NULL server). // // Arguments: pszServerName - Name of targtet server/domain or NULL. // Credentials - Credentials to use for the connection. // Currently this is not used. // phLsaPolicy - Return ptr for lsa policy handle. // // Returns: S_OK or any valid error code. // // Modifies: phLsaPolicy. // //---------------------------------------------------------------------------- HRESULT GetLsaPolicyHandle( LPWSTR pszServerName, CCredentials &Credentials, PLSA_HANDLE phLsaPolicy ) { HRESULT hr = S_OK; DWORD dwStatus = NO_ERROR; NTSTATUS ntStatus = STATUS_SUCCESS; DWORD dwErr; DWORD dwLen = 0; LPWSTR pszServer = NULL; BOOL fNullServer = FALSE; LSA_OBJECT_ATTRIBUTES lsaObjectAttributes; LSA_UNICODE_STRING lsaSystemName; WCHAR szDomainName[MAX_PATH]; WCHAR szServerName[MAX_PATH]; memset(&lsaObjectAttributes, 0, sizeof(LSA_OBJECT_ATTRIBUTES)); // // First most common case of serverless paths. // if (!pszServerName) { dwStatus = GetDomainDNSNameForDomain( NULL, FALSE, // do not force verify FALSE, // does not need to be writable szServerName, szDomainName ); // // If we succeeded we will use the name returned, // otherwise we will go with NULL. // if (dwStatus == NO_ERROR) { pszServer = szServerName; } else { fNullServer = TRUE; } } else { pszServer = pszServerName; } if (pszServer) { dwLen = wcslen(pszServer); } lsaSystemName.Buffer = pszServer; lsaSystemName.Length = dwLen * sizeof(WCHAR); lsaSystemName.MaximumLength = lsaSystemName.Length; // // First attempt at opening policy handle. // ntStatus = LsaOpenPolicy( &lsaSystemName, &lsaObjectAttributes, POLICY_LOOKUP_NAMES, phLsaPolicy ); if (ntStatus != STATUS_SUCCESS) { // // Irrespective of failure should retry if we have not already // tried with a NULL serverName. // if (!fNullServer) { fNullServer = TRUE; lsaSystemName.Buffer = NULL; lsaSystemName.Length = 0; lsaSystemName.MaximumLength = 0; ntStatus = LsaOpenPolicy( &lsaSystemName, &lsaObjectAttributes, POLICY_LOOKUP_NAMES, phLsaPolicy ); } hr = HRESULT_FROM_WIN32( LsaNtStatusToWinError(ntStatus) ); BAIL_ON_FAILURE(hr); } error: RRETURN(hr); } //+--------------------------------------------------------------------------- // Function: GetNamesFromSids - helper routine. // // Synopsis: Simple helper routine that calls LsaLookupSids and if the // the error returned is ERROR_SOME_NOT_MAPPED, then the hr is // set S_OK. // // Arguments: hLsaPolicy - LSA_HANDLE to do the lookup on. // pSidArray - Array of sid's top lookup. // dwSidCount - Number of sids to translate. // ppLsaRefDomList - Ret value for domain list. // ppLsaNames - Ret value for name list. // // Returns: S_OK or any valid error code. // // Modifies: n/a. // //---------------------------------------------------------------------------- HRESULT GetNamesFromSids( LSA_HANDLE hLsaPolicy, PSID *pSidArray, DWORD dwSidCount, PLSA_REFERENCED_DOMAIN_LIST *ppLsaRefDomList, PLSA_TRANSLATED_NAME *ppLsaNames ) { HRESULT hr = S_OK; NTSTATUS ntStatus; ntStatus = LsaLookupSids( hLsaPolicy, dwSidCount, pSidArray, ppLsaRefDomList, ppLsaNames ); // even if the above call fails, we don't want to bail out since even if all the name resolving fails // we still want to try to use the stringlized sid RRETURN(hr); } //+--------------------------------------------------------------------------- // Function: GetNamesForSidFromArray - helper routine. // // Synopsis: Given the position of the ace and the retrun value from // LsaLookupSids, constructs the actual name of the trustee. // // Arguments: dwAceNumber - Position of the ace in the array. // pLsaRefDoms - List of reference domains. // pLsaNames - List of LSA names. // ppszFriendlyName - Return string pointer. // // Returns: S_OK or any valid error code. // // Modifies: n/a. // //---------------------------------------------------------------------------- HRESULT GetNameForSidFromArray( DWORD dwAceNumber, LSA_REFERENCED_DOMAIN_LIST *pLsaRefDoms, LSA_TRANSLATED_NAME *pLsaNames, LPWSTR * ppszFriendlyName ) { HRESULT hr = S_OK; DWORD dwLengthDomain; DWORD dwLengthName = 0; BOOL fDomainInvalid = FALSE; BOOL fNameInvalid = FALSE; LPWSTR pszName = NULL; *ppszFriendlyName = NULL; if (!pLsaNames) { RRETURN(hr = E_FAIL); } switch (pLsaNames[dwAceNumber].Use) { case SidTypeDomain: fNameInvalid = TRUE; break; case SidTypeInvalid: fNameInvalid = TRUE; fDomainInvalid = TRUE; break; case SidTypeUnknown: fNameInvalid = TRUE; fDomainInvalid = TRUE; break; case SidTypeWellKnownGroup: if (pLsaNames[dwAceNumber].DomainIndex < 0 ) { fDomainInvalid = TRUE; } break; default: // // Name and domain are valid. // fDomainInvalid = FALSE; fNameInvalid = FALSE; } if (!fNameInvalid) { dwLengthName = ((pLsaNames[dwAceNumber]).Name).Length + sizeof(WCHAR); } // // Process domain if valid. // if (!fDomainInvalid) { DWORD domainIndex = pLsaNames[dwAceNumber].DomainIndex; LSA_UNICODE_STRING lsaString; // // Need to make sure that the index is valid. // if (domainIndex > pLsaRefDoms->Entries) { BAIL_ON_FAILURE(hr = E_FAIL); } lsaString = ((pLsaRefDoms->Domains)[domainIndex]).Name; // // Add sizeof(WCHAR) for the trailing \0. // dwLengthDomain = lsaString.Length + sizeof(WCHAR); if (lsaString.Length > 0) { pszName = (LPWSTR) AllocADsMem( dwLengthDomain + dwLengthName); if (!pszName) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } memcpy( pszName, lsaString.Buffer, lsaString.Length ); } } if (!fNameInvalid) { LSA_UNICODE_STRING lsaNameString = (pLsaNames[dwAceNumber]).Name; // // Length of pszName is zero if the group name is Everyone but // there is still a domain name component. // if (!fDomainInvalid && pszName && wcslen(pszName) ) { wcscat(pszName, L"\\"); } else { pszName = (LPWSTR) AllocADsMem(dwLengthName); if (!pszName) { BAIL_ON_FAILURE (hr = E_OUTOFMEMORY); } } memcpy( fDomainInvalid ? pszName : (pszName + wcslen(pszName)), lsaNameString.Buffer, lsaNameString.Length ); } *ppszFriendlyName = pszName; RRETURN(hr); error: if (pszName) { FreeADsMem(pszName); } RRETURN(hr); } HRESULT ConvertSecDescriptorToVariant( LPWSTR pszServerName, CCredentials& Credentials, PSECURITY_DESCRIPTOR pSecurityDescriptor, VARIANT * pVarSec, BOOL fNTDS ) { 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; VariantInit(pVarSec); memset(&varSACL, 0, sizeof(VARIANT)); memset(&varDACL, 0, sizeof(VARIANT)); if (!pSecurityDescriptor) { RRETURN(E_FAIL); } // // Control & Revision // dwRet = GetSecurityDescriptorControl( pSecurityDescriptor, &wControl, &dwRevision ); if (!dwRet){ hr = HRESULT_FROM_WIN32(GetLastError()); BAIL_ON_FAILURE(hr); } // // Owner // dwRet = GetSecurityDescriptorOwner( pSecurityDescriptor, (PSID *)&pOwnerSidAddress, &fOwnerDefaulted ); if (!dwRet){ hr = HRESULT_FROM_WIN32(GetLastError()); BAIL_ON_FAILURE(hr); } if (pOwnerSidAddress) { // // For Owner and Group, we will convert the sid in old way without optimization // hr = ConvertSidToFriendlyName2( pszServerName, Credentials, pOwnerSidAddress, &pszOwner, fNTDS ); BAIL_ON_FAILURE(hr); } // // Group // dwRet = GetSecurityDescriptorGroup( pSecurityDescriptor, (PSID *)&pGroupSidAddress, &fOwnerDefaulted ); if (!dwRet){ hr = HRESULT_FROM_WIN32(GetLastError()); BAIL_ON_FAILURE(hr); } if (pGroupSidAddress) { // // For Owner and Group, we will convert the sid in old way without optimization // hr = ConvertSidToFriendlyName2( pszServerName, Credentials, pGroupSidAddress, &pszGroup, fNTDS ); BAIL_ON_FAILURE(hr); } // // DACL // dwRet = GetSecurityDescriptorDacl( pSecurityDescriptor, &fDaclPresent, (PACL*)&pDACLAddress, &fDaclDefaulted ); if (!dwRet){ hr = HRESULT_FROM_WIN32(GetLastError()); BAIL_ON_FAILURE(hr); } if (pDACLAddress) { hr = ConvertACLToVariant( pszServerName, Credentials, (PACL)pDACLAddress, &varDACL, fNTDS ); BAIL_ON_FAILURE(hr); } // // SACL // dwRet = GetSecurityDescriptorSacl( pSecurityDescriptor, &fSaclPresent, (PACL *)&pSACLAddress, &fSaclDefaulted ); if (!dwRet){ hr = HRESULT_FROM_WIN32(GetLastError()); BAIL_ON_FAILURE(hr); } if (pSACLAddress) { hr = ConvertACLToVariant( pszServerName, Credentials, (PACL)pSACLAddress, &varSACL, fNTDS ); BAIL_ON_FAILURE(hr); } // // Construct an IADsSecurityDescriptor with the data // retrieved from the raw SD // hr = CoCreateInstance( CLSID_SecurityDescriptor, NULL, CLSCTX_INPROC_SERVER, IID_IADsSecurityDescriptor, (void **)&pSecDes ); BAIL_ON_FAILURE(hr); hr = pSecDes->put_Owner(pszOwner); BAIL_ON_FAILURE(hr); 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); // // Construct a VARIANT with the IADsSecurityDescriptor // V_VT(pVarSec) = VT_DISPATCH; V_DISPATCH(pVarSec) = pDispatch; error: VariantClear(&varSACL); VariantClear(&varDACL); if (pszOwner) { FreeADsStr(pszOwner); } if (pszGroup) { FreeADsStr(pszGroup); } if (pSecDes) { pSecDes->Release(); } RRETURN(hr); } HRESULT ConvertSidToFriendlyName( LPWSTR pszServerName, CCredentials& Credentials, PSID pSid, LPWSTR * ppszAccountName, BOOL fNTDS ) { HRESULT hr = S_OK; SID_NAME_USE eUse; WCHAR szAccountName[MAX_PATH]; WCHAR szDomainName[MAX_PATH]; WCHAR szServerName[MAX_PATH]; DWORD dwLen = 0; DWORD dwRet = 0; LPWSTR pszAccountName = NULL; DWORD dwAcctLen = 0; DWORD dwDomainLen = 0; #if 0 /************************************************************** // // parse Trustee and determine whether its NTDS or U2 // if (fNTDS) { dwAcctLen = sizeof(szAccountName); dwDomainLen = sizeof(szDomainName); dwRet = LookupAccountSid( pszServerName, pSid, szAccountName, &dwAcctLen, szDomainName, &dwDomainLen, (PSID_NAME_USE)&eUse ); // // Try with NULL server name if we have not already // done that for error cases. // if (!dwRet && pszServerName) { dwRet = LookupAccountSid( NULL, pSid, szAccountName, &dwAcctLen, szDomainName, &dwDomainLen, (PSID_NAME_USE)&eUse ); } // // If using serverless paths, try it on the DC if it // failed (which will happen if we're trying to resolve // something like "BUILTIN\Print Operators" on a member // computer) // if (!dwRet && !pszServerName) { dwAcctLen = sizeof(szAccountName); dwDomainLen = sizeof(szDomainName); DWORD dwStatus = GetDomainDNSNameForDomain( NULL, FALSE, // don't force verify FALSE, // not writable szServerName, szDomainName ); if (dwStatus == NO_ERROR) { dwRet = LookupAccountSid( szServerName, pSid, szAccountName, &dwAcctLen, szDomainName, &dwDomainLen, (PSID_NAME_USE)&eUse ); // // If the lookup failed because the server was unavailable, try to get // the server again, this time forcing DsGetDcName to do rediscovery // if (!dwRet && (GetLastError() == RPC_S_SERVER_UNAVAILABLE)) { dwStatus = GetDomainDNSNameForDomain( NULL, TRUE, // force verify FALSE,// not writable szServerName, szDomainName ); if (dwStatus == NO_ERROR) { dwRet = LookupAccountSid( szServerName, pSid, szAccountName, &dwAcctLen, szDomainName, &dwDomainLen, (PSID_NAME_USE)&eUse ); } } } } if (!dwRet) { hr = HRESULT_FROM_WIN32(GetLastError()); }else { dwLen = wcslen(szAccountName) + wcslen(szDomainName) + 1 + 1; pszAccountName = (LPWSTR)AllocADsMem(dwLen * sizeof(WCHAR)); if (!pszAccountName) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } if (szDomainName[0] && szAccountName[0]) { wsprintf(pszAccountName,L"%s\\%s",szDomainName, szAccountName); }else if (szAccountName[0]) { wsprintf(pszAccountName,L"%s", szAccountName); } *ppszAccountName = pszAccountName; } }else { *****************************************************************/ #endif if (!fNTDS) { hr = ConvertSidToU2Trustee( pszServerName, Credentials, pSid, szAccountName ); if (SUCCEEDED(hr)) { pszAccountName = AllocADsStr(szAccountName); if (!pszAccountName) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } *ppszAccountName = pszAccountName; } } else { // // This is NTDS case where we need to stringize SID. // hr = E_FAIL; } if (FAILED(hr)) { hr = ConvertSidToString( pSid, szAccountName ); BAIL_ON_FAILURE(hr); pszAccountName = AllocADsStr(szAccountName); if (!pszAccountName) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } *ppszAccountName = pszAccountName; } error: RRETURN(hr); } HRESULT ConvertSidToFriendlyName2( LPWSTR pszServerName, CCredentials& Credentials, PSID pSid, LPWSTR * ppszAccountName, BOOL fNTDS ) { HRESULT hr = S_OK; SID_NAME_USE eUse; WCHAR szAccountName[MAX_PATH]; WCHAR szDomainName[MAX_PATH]; WCHAR szServerName[MAX_PATH]; DWORD dwLen = 0; DWORD dwRet = 0; LPWSTR pszAccountName = NULL; DWORD dwAcctLen = 0; DWORD dwDomainLen = 0; // // parse Trustee and determine whether its NTDS or U2 // if (fNTDS) { dwAcctLen = MAX_PATH; dwDomainLen = MAX_PATH; // // Servername is specified // if (pszServerName) { dwRet = LookupAccountSid( pszServerName, pSid, szAccountName, &dwAcctLen, szDomainName, &dwDomainLen, (PSID_NAME_USE)&eUse ); } // // Servername not specified // else { // // If using serverless paths, try it first on the DC // DWORD dwStatus = GetDomainDNSNameForDomain( NULL, FALSE, // don't force verify FALSE, // not writable szServerName, szDomainName ); if (dwStatus == NO_ERROR) { dwRet = LookupAccountSid( szServerName, pSid, szAccountName, &dwAcctLen, szDomainName, &dwDomainLen, (PSID_NAME_USE)&eUse ); // // If the lookup failed because the server was unavailable, try to get // the server again, this time forcing DsGetDcName to do rediscovery // if (!dwRet && (GetLastError() == RPC_S_SERVER_UNAVAILABLE)) { dwStatus = GetDomainDNSNameForDomain( NULL, TRUE, // force verify FALSE,// not writable szServerName, szDomainName ); if (dwStatus == NO_ERROR) { dwRet = LookupAccountSid( szServerName, pSid, szAccountName, &dwAcctLen, szDomainName, &dwDomainLen, (PSID_NAME_USE)&eUse ); } } } } // // At last try with NULL server name // if (!dwRet) { dwAcctLen = MAX_PATH; dwDomainLen = MAX_PATH; dwRet = LookupAccountSid( NULL, pSid, szAccountName, &dwAcctLen, szDomainName, &dwDomainLen, (PSID_NAME_USE)&eUse ); } if (!dwRet) { hr = HRESULT_FROM_WIN32(GetLastError()); }else { dwLen = wcslen(szAccountName) + wcslen(szDomainName) + 1 + 1; pszAccountName = (LPWSTR)AllocADsMem(dwLen * sizeof(WCHAR)); if (!pszAccountName) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } if (szDomainName[0] && szAccountName[0]) { wsprintf(pszAccountName,L"%s\\%s",szDomainName, szAccountName); }else if (szAccountName[0]) { wsprintf(pszAccountName,L"%s", szAccountName); } *ppszAccountName = pszAccountName; } } else { hr = ConvertSidToU2Trustee( pszServerName, Credentials, pSid, szAccountName ); if (SUCCEEDED(hr)) { pszAccountName = AllocADsStr(szAccountName); if (!pszAccountName) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } *ppszAccountName = pszAccountName; } } if (FAILED(hr)) { hr = ConvertSidToString( pSid, szAccountName ); BAIL_ON_FAILURE(hr); pszAccountName = AllocADsStr(szAccountName); if (!pszAccountName) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } *ppszAccountName = pszAccountName; } error: RRETURN(hr); } HRESULT ConvertACLToVariant( LPWSTR pszServerName, CCredentials& Credentials, PACL pACL, PVARIANT pvarACL, BOOL fNTDS ) { IADsAccessControlList * pAccessControlList = NULL; IDispatch * pDispatch = NULL; LPWSTR pszFriendlyName = 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; LSA_HANDLE hLsaPolicy = NULL; PLSA_REFERENCED_DOMAIN_LIST pLsaRefDomList = NULL; PLSA_TRANSLATED_NAME pLsaNames = NULL; PSID *pSidArray = NULL; memset(&AclSize, 0, sizeof(ACL_SIZE_INFORMATION)); memset(&AclRevision, 0, sizeof(ACL_REVISION_INFORMATION)); dwStatus = GetAclInformation( pACL, &AclSize, sizeof(ACL_SIZE_INFORMATION), AclSizeInformation ); // // Status should be nonzero for success // if (!dwStatus) { hr = HRESULT_FROM_WIN32(GetLastError()); BAIL_ON_FAILURE(hr); } dwStatus = GetAclInformation( pACL, &AclRevision, sizeof(ACL_REVISION_INFORMATION), AclRevisionInformation ); if (!dwStatus) { hr = HRESULT_FROM_WIN32(GetLastError()); BAIL_ON_FAILURE(hr); } dwAceCount = AclSize.AceCount; dwAclRevision = AclRevision.AclRevision; VariantInit(pvarACL); hr = CoCreateInstance( CLSID_AccessControlList, NULL, CLSCTX_INPROC_SERVER, IID_IADsAccessControlList, (void **)&pAccessControlList ); BAIL_ON_FAILURE(hr); // // Do this only when we actually have ACE // if(dwAceCount > 0) { // // Sid lookup can be optimized only for NT style SD's. // SiteServer style SD's will continue to be processed as before. // if (fNTDS) { // // To speed up the conversion of SID's to trustees, an array of // SID's to lookup is built and the whole array processed in one // shot. Then the result of the Lookup is used in contstructing // the individual ACE's. // pSidArray = (PSID*) AllocADsMem(sizeof(PSID) * dwAceCount); if (!pSidArray) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } for (i = 0; i < dwAceCount; i++) { dwStatus = GetAce(pACL, i , (void **) &pAceAddress); if (!dwStatus) { BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(GetLastError())); } pSidArray[i] = ComputeSidFromAceAddress(pAceAddress); // // Sanity check we should always have valid data. // if (!pSidArray[i]) { BAIL_ON_FAILURE(hr = E_FAIL); } } hr = GetLsaPolicyHandle( pszServerName, Credentials, &hLsaPolicy ); // // Should we just convert to string SID's ? // BAIL_ON_FAILURE(hr); hr = GetNamesFromSids( hLsaPolicy, pSidArray, dwAceCount, &pLsaRefDomList, &pLsaNames ); BAIL_ON_FAILURE(hr); } for (i = 0; i < dwAceCount; i++) { if (pszFriendlyName) { FreeADsStr(pszFriendlyName); pszFriendlyName = NULL; } dwStatus = GetAce(pACL, i, (void **)&pAceAddress); // // Need to verify we got back the ace correctly. // if (!dwStatus) { BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(GetLastError())); } if(fNTDS) { hr = GetNameForSidFromArray( i, pLsaRefDomList, pLsaNames, &pszFriendlyName ); } // // We can ignore the failure. // On failure pszFriendlyName is set to NULL in which case // we will convert to stringised sid format (for NTDS of course). // hr = ConvertAceToVariant( pszServerName, pszFriendlyName, Credentials, pAceAddress, (PVARIANT)&varAce, fNTDS ); // // If we cannot convert an ACE we should error out. // BAIL_ON_FAILURE(hr); hr = pAccessControlList->AddAce(V_DISPATCH(&varAce)); VariantClear(&varAce); BAIL_ON_FAILURE(hr); dwNewAceCount++; } } 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(); } if (pszFriendlyName) { FreeADsStr(pszFriendlyName); } if (pLsaNames) { LsaFreeMemory(pLsaNames); } if (pLsaRefDomList) { LsaFreeMemory(pLsaRefDomList); } if (hLsaPolicy) { LsaClose(hLsaPolicy); } if(pSidArray) { FreeADsMem(pSidArray); } RRETURN(hr); } HRESULT ConvertAceToVariant( LPWSTR pszServerName, LPWSTR pszTrusteeName, CCredentials& Credentials, PBYTE pAce, PVARIANT pvarAce, BOOL fNTDS ) { IADsAccessControlEntry * pAccessControlEntry = NULL; IDispatch * pDispatch = NULL; IADsAcePrivate *pPrivAce = NULL; DWORD dwAceType = 0; DWORD dwAceFlags = 0; DWORD dwAccessMask = 0; DWORD dwLenSid = 0; DWORD dwErr = 0; LPWSTR pszAccountName = NULL; PACE_HEADER pAceHeader = NULL; LPBYTE pSidAddress = NULL; LPBYTE pOffset = NULL; DWORD dwFlags = 0; GUID ObjectGUID; GUID InheritedObjectGUID; BSTR bstrObjectGUID = NULL; BSTR bstrInheritedObjectGUID = NULL; HRESULT hr = S_OK; 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)); hr = BuildADsGuid(ObjectGUID, &bstrObjectGUID); BAIL_ON_FAILURE(hr); pOffset += sizeof (GUID); } if (dwFlags & ACE_INHERITED_OBJECT_TYPE_PRESENT) { memcpy(&InheritedObjectGUID, pOffset, sizeof(GUID)); hr = BuildADsGuid(InheritedObjectGUID, &bstrInheritedObjectGUID); BAIL_ON_FAILURE(hr); pOffset += sizeof (GUID); } pSidAddress = pOffset; break; default: break; } if (pSidAddress) { // // Nt4 does not reset the last error correctly. // SetLastError(NO_ERROR); dwLenSid = GetLengthSid(pSidAddress); if ((dwErr = GetLastError()) != NO_ERROR) { BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(dwErr)); } } else { // // We should always have a valid sid address here. // Should we be bailing here ? Or for that matter, // should be bail on the default cluase of the switch ? // dwLenSid = 0; } // // Call the old function only if we could not resolve the name // if (!pszTrusteeName) { hr = ConvertSidToFriendlyName( pszServerName, Credentials, pSidAddress, &pszAccountName, fNTDS ); } if (FAILED(hr)){ pszAccountName = AllocADsStr(L"Unknown Trustee"); if (!pszAccountName) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } } // // 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(bstrObjectGUID); } if (dwFlags & ACE_INHERITED_OBJECT_TYPE_PRESENT) { // // Add in the Inherited Object Type GUID // hr = pAccessControlEntry->put_InheritedObjectType( bstrInheritedObjectGUID ); } // // This is a string, so need to check the ecode. We use the // friendlyName if that was set and if not the pszAccountName. // hr = pAccessControlEntry->put_Trustee( pszTrusteeName ? pszTrusteeName : pszAccountName ); BAIL_ON_FAILURE(hr); if (pSidAddress) { // // We should now put the SID on this ACE for quick reverse lookup. // hr = pAccessControlEntry->QueryInterface( IID_IADsAcePrivate, (void **)&pPrivAce ); if SUCCEEDED(hr) { hr = pPrivAce->putSid( pSidAddress, dwLenSid ); } // // No bail on failure here as it is not a critical failure // } hr = pAccessControlEntry->QueryInterface( IID_IDispatch, (void **)&pDispatch ); BAIL_ON_FAILURE(hr); V_DISPATCH(pvarAce) = pDispatch; V_VT(pvarAce) = VT_DISPATCH; cleanup: if (pszAccountName) { FreeADsStr(pszAccountName); } if (pAccessControlEntry) { pAccessControlEntry->Release(); } if (pPrivAce) { pPrivAce->Release(); } if (bstrObjectGUID) { ADsFreeString(bstrObjectGUID); } if (bstrInheritedObjectGUID) { ADsFreeString(bstrInheritedObjectGUID); } RRETURN(hr); error: if (pDispatch) { pDispatch->Release(); } goto cleanup; } //+--------------------------------------------------------------------------- // Function: ComputeSidFromAceAddress - helper routine. // // Synopsis: Returns the pointer to the SID, given a ptr to an ACE. // // Arguments: pAce - ptr to the ACE. // // Returns: NULL on error or valid PSID. // // Modifies: N/A. // //---------------------------------------------------------------------------- PSID ComputeSidFromAceAddress( LPBYTE pAce ) { PSID pSidRetVal = NULL; PACE_HEADER pAceHeader = NULL; LPBYTE pOffset = NULL; DWORD dwAceType, dwAceFlags, dwAccessMask; DWORD dwFlags; 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: pSidRetVal = (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) { pOffset += sizeof (GUID); } if (dwFlags & ACE_INHERITED_OBJECT_TYPE_PRESENT) { pOffset += sizeof (GUID); } pSidRetVal = pOffset; break; default: break; } // end of switch case. return pSidRetVal; }