#ifndef _AUSRUTIL_H #define _AUSRUTIL_H #include #include "EscStr.h" #include #include #include #define SECURITY_WIN32 #include enum NameContextType { NAMECTX_SCHEMA = 0, NAMECTX_CONFIG = 1, NAMECTX_COUNT }; // ---------------------------------------------------------------------------- // GetADNamingContext() // ---------------------------------------------------------------------------- inline HRESULT GetADNamingContext(NameContextType ctx, LPCWSTR* ppszContextDN) { const static LPCWSTR pszContextName[NAMECTX_COUNT] = { L"schemaNamingContext", L"configurationNamingContext"}; static CString strContextDN[NAMECTX_COUNT]; HRESULT hr = S_OK; if (strContextDN[ctx].IsEmpty()) { CComVariant var; CComPtr pObj; hr = ADsGetObject(L"LDAP://rootDSE", IID_IADs, (void**)&pObj); if (SUCCEEDED(hr)) { CComBSTR bstrProp = pszContextName[ctx]; hr = pObj->Get( bstrProp, &var ); if (SUCCEEDED(hr)) { strContextDN[ctx] = var.bstrVal; *ppszContextDN = strContextDN[ctx]; } } } else { *ppszContextDN = strContextDN[ctx]; hr = S_OK; } return hr; } //-------------------------------------------------------------------------- // EnableButton // // Enables or disables a dialog control. If the control has the focus when // it is disabled, the focus is moved to the next control //-------------------------------------------------------------------------- inline void EnableButton(HWND hwndDialog, int iCtrlID, BOOL bEnable) { HWND hWndCtrl = ::GetDlgItem(hwndDialog, iCtrlID); ATLASSERT(::IsWindow(hWndCtrl)); if (!bEnable && ::GetFocus() == hWndCtrl) { HWND hWndNextCtrl = ::GetNextDlgTabItem(hwndDialog, hWndCtrl, FALSE); if (hWndNextCtrl != NULL && hWndNextCtrl != hWndCtrl) { ::SetFocus(hWndNextCtrl); } } ::EnableWindow(hWndCtrl, bEnable); } // ---------------------------------------------------------------------------- // ErrorMsg() // ---------------------------------------------------------------------------- inline void ErrorMsg(UINT uiError, UINT uiTitle) { CString csError; CString csTitle; csError.LoadString(uiError); csTitle.LoadString(uiTitle); ::MessageBox(NULL, (LPCWSTR)csError, (LPCWSTR)csTitle, MB_OK | MB_TASKMODAL | MB_ICONERROR); } inline BOOL StrContainsDBCS(LPCTSTR szIn) { if( !szIn ) return FALSE; BOOL bFound = FALSE; TCHAR *pch = NULL; for ( pch=(LPTSTR)szIn; *pch && !bFound; pch=_tcsinc(pch) ) { if ( IsDBCSLeadByte((BYTE)*pch) ) { bFound = TRUE; } } return bFound; } inline BOOL LdapToDCName(LPCTSTR pszPath, LPTSTR pszOutBuf, int nOutBufSize) { if( !pszPath || !pszOutBuf || !nOutBufSize ) return FALSE; pszOutBuf[0] = 0; TCHAR* pszTemp = _tcsstr( pszPath, _T("DC=") ); if( !pszTemp ) return FALSE; DWORD dwSize = nOutBufSize; BOOLEAN bSuccess = TranslateName( pszTemp, NameFullyQualifiedDN, NameCanonical, pszOutBuf, &dwSize ); if( bSuccess && (dwSize > 2) ) { if( pszOutBuf[dwSize-2] == _T('/') ) { pszOutBuf[dwSize-2] = 0; } } return (BOOL)bSuccess; } // ---------------------------------------------------------------------------- // FindADsObject() // // szFilterFmt must be of the format "(|(cn=%1)(ou=%1))" // NOTE: szFilterFmt must contain ONLY %1's.. i.e. %2 is right out! // ---------------------------------------------------------------------------- inline HRESULT FindADsObject( LPCTSTR szOU, LPCTSTR szObject, LPCTSTR szFilterFmt, CString &csResult, DWORD dwRetType/*=0*/, BOOL bRoot/*=FALSE*/ ) { if( !szOU || !szObject || !szFilterFmt ) return E_POINTER; // Find out if the szObject contains any '(' or ')'s.. if so then we have to exit. if ( _tcschr(szObject, _T('(')) || _tcschr(szObject, _T(')')) ) { return S_FALSE; } HRESULT hr = S_OK; CString csTmp = szOU; CString csOU = L"LDAP://"; TCHAR *pch = NULL; if ( bRoot ) { csTmp.MakeUpper(); pch = _tcsstr( (LPCTSTR)csTmp, L"DC=" ); // Find the first DC= if ( !pch ) return E_FAIL; csOU += pch; // Append from the DC= on. if ( (pch = _tcschr((LPCTSTR)csOU + 7, L'/')) != NULL ) { // Hmmm. . something was after the DC='s... I don't even know // if that's allowed. // (e.g. LDAP://DC=ted,DC=microsoft,DC=com/foo) // If so, let's end the string at the / *pch = 0; } } else { csTmp.MakeUpper(); pch = _tcsstr( (LPCTSTR)csTmp, L"LDAP://" ); // Did the string include the LDAP://? if ( !pch ) { csOU += csTmp; } else { csOU = csTmp; } // Now csOU contains the LDAP:// for sure. } // Set query parameters CComPtr spDirSearch = NULL; ADS_SEARCH_HANDLE hSearch; // Handle used for searching. ADS_SEARCH_COLUMN col; // Used to hold the current column. CString csFilter; LPTSTR pszAttr[] = { _T("cn"), _T("distinguishedName"), _T("description"), _T("sAMAccountName"), _T("mailNickname") }; DWORD dwCount = sizeof(pszAttr) / sizeof(LPTSTR); csFilter.FormatMessage(szFilterFmt, szObject); // Open our search object. hr = ::ADsOpenObject(const_cast((LPCTSTR)csOU), NULL, NULL, ADS_SECURE_AUTHENTICATION, IID_IDirectorySearch, (void**)&spDirSearch); if ( !SUCCEEDED(hr) ) { _ASSERT(FALSE); return hr; } // Search for out object. hr = spDirSearch->ExecuteSearch(const_cast((LPCTSTR)csFilter), pszAttr, dwCount, &hSearch); if ( !SUCCEEDED(hr) ) { return(hr); } if ( spDirSearch->GetNextRow(hSearch) == S_ADS_NOMORE_ROWS ) { spDirSearch->CloseSearchHandle(hSearch); return(E_FAIL); } // If we got to here, then we got the object, so let's get the LDAP path to the // object so that we can return it to the caller. hr = spDirSearch->GetColumn(hSearch, pszAttr[dwRetType], &col); if ( !SUCCEEDED(hr) ) { _ASSERT(FALSE); csResult = _T(""); } else { csResult = col.pADsValues->CaseExactString; spDirSearch->FreeColumn(&col); } spDirSearch->CloseSearchHandle(hSearch); return(S_OK); } inline tstring GetDomainPath( LPCTSTR lpServer ) { if( !lpServer ) return _T(""); // get the domain information CComVariant var; tstring strRet = _T(""); TCHAR pszString[MAX_PATH*2] = {0}; _sntprintf( pszString, (MAX_PATH*2)-1, L"LDAP://%s/rootDSE", lpServer ); CComPtr pDS = NULL; HRESULT hr = ::ADsGetObject( pszString, IID_IADs, (void**)&pDS ); if( SUCCEEDED(hr) ) { CComBSTR bstrProp = _T("defaultNamingContext"); hr = pDS->Get( bstrProp, &var ); } if( SUCCEEDED(hr) && (V_VT(&var) == VT_BSTR) ) { strRet = V_BSTR( &var ); } return strRet; } //+---------------------------------------------------------------------------- // // Function: RemoveTrailingWhitespace // // Synopsis: Trailing white space is replaced by NULLs. // //----------------------------------------------------------------------------- inline void RemoveTrailingWhitespace(LPTSTR pszIn) { if( !pszIn ) return; int nLen = _tcslen(pszIn); while( nLen ) { if( !iswspace(pszIn[nLen - 1]) ) { return; } pszIn[nLen - 1] = L'\0'; nLen--; } } inline tstring StrFormatSystemError( HRESULT hrErr ) { tstring strError = _T(""); LPVOID lpMsgBuf = NULL; // look up the error from the system if ( ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, hrErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL )) { if( lpMsgBuf ) { strError = (LPTSTR)lpMsgBuf; LocalFree( lpMsgBuf ); } } // return the error string return strError; } inline tstring StrGetWindowText( HWND hWnd ) { if( !hWnd || !IsWindow(hWnd) ) { return _T(""); } TSTRING strRet = _T(""); INT iLen = GetWindowTextLength(hWnd); TCHAR* pszText = new TCHAR[ iLen + 1 ]; if ( pszText ) { if ( GetWindowText(hWnd, pszText, iLen + 1) ) { strRet = pszText; } delete[] pszText; } return strRet; } inline HRESULT SetSecInfoMask( LPUNKNOWN punk, SECURITY_INFORMATION si ) { HRESULT hr = E_INVALIDARG; if( punk ) { CComPtr spOptions; hr = punk->QueryInterface( IID_IADsObjectOptions, (void**)&spOptions ); if( SUCCEEDED(hr) ) { VARIANT var; VariantInit( &var ); V_VT( &var ) = VT_I4; V_I4( &var ) = si; hr = spOptions->SetOption( ADS_OPTION_SECURITY_MASK, var ); } } return hr; } //+--------------------------------------------------------------------------- // // Function: GetSDForDsObject // Synopsis: Reads the security descriptor from the specied DS object // It only reads the DACL portion of the security descriptor // // Arguments: [IN pDsObject] -- DS object // [ppDACL] --pointer to dacl in ppSD is returned here // [OUT ppSD] -- Security descriptor returned here. // calling API must free this by calling LocalFree // // Notes: The returned security descriptor must be freed with LocalFree // //---------------------------------------------------------------------------- inline HRESULT GetSDForDsObject( IDirectoryObject* pDsObject, PACL* ppDACL, PSECURITY_DESCRIPTOR* ppSD ) { if(!pDsObject || !ppSD) return E_POINTER; *ppSD = NULL; if(ppDACL) { *ppDACL = NULL; } HRESULT hr = S_OK; PADS_ATTR_INFO pSDAttributeInfo = NULL; WCHAR const c_szSDProperty[] = L"nTSecurityDescriptor"; LPWSTR pszProperty = (LPWSTR)c_szSDProperty; // Set the SECURITY_INFORMATION mask to DACL_SECURITY_INFORMATION hr = SetSecInfoMask(pDsObject, DACL_SECURITY_INFORMATION); DWORD dwAttributesReturned; if( SUCCEEDED(hr) ) { // Read the security descriptor attribute hr = pDsObject->GetObjectAttributes( &pszProperty, 1, &pSDAttributeInfo, &dwAttributesReturned ); if(SUCCEEDED(hr) && !pSDAttributeInfo) { hr = E_FAIL; } } if( SUCCEEDED(hr) ) { if((ADSTYPE_NT_SECURITY_DESCRIPTOR == pSDAttributeInfo->dwADsType) && (ADSTYPE_NT_SECURITY_DESCRIPTOR == pSDAttributeInfo->pADsValues->dwType)) { *ppSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, pSDAttributeInfo->pADsValues->SecurityDescriptor.dwLength); if (!*ppSD) { hr = E_OUTOFMEMORY; } } else { hr = E_FAIL; } } if( SUCCEEDED(hr) ) { CopyMemory( *ppSD, pSDAttributeInfo->pADsValues->SecurityDescriptor.lpValue, pSDAttributeInfo->pADsValues->SecurityDescriptor.dwLength ); if( ppDACL ) { BOOL bDaclPresent,bDaclDeafulted; if( !GetSecurityDescriptorDacl(*ppSD, &bDaclPresent, ppDACL, &bDaclDeafulted) ) { DWORD dwErr = GetLastError(); hr = HRESULT_FROM_WIN32(dwErr); } } } if( pSDAttributeInfo ) { FreeADsMem( pSDAttributeInfo ); } if( FAILED(hr) ) { if(*ppSD) { LocalFree(*ppSD); *ppSD = NULL; if(ppDACL) *ppDACL = NULL; } } return hr; } //+--------------------------------------------------------------------------- // // Function: GetSDForDsObjectPath // Synopsis: Reads the security descriptor from the specied DS object // It only reads the DACL portion of the security descriptor // // Arguments: [IN pszObjectPath] -- LDAP Path of ds object // [ppDACL] --pointer to dacl in ppSD is returned here // [OUT ppSD] -- Security descriptor returned here. // calling API must free this by calling LocalFree // // Notes: The returned security descriptor must be freed with LocalFree // //---------------------------------------------------------------------------- inline HRESULT GetSDForDsObjectPath( LPCWSTR pszObjectPath, PACL* ppDACL, PSECURITY_DESCRIPTOR* ppSecurityDescriptor ) { if(!pszObjectPath || !ppSecurityDescriptor) return E_POINTER; CComPtr spDsObject = NULL; HRESULT hr = ADsGetObject(pszObjectPath, IID_IDirectoryObject,(void**)&spDsObject); if(SUCCEEDED(hr)) { hr = GetSDForDsObject( spDsObject, ppDACL, ppSecurityDescriptor ); } return hr; } //+--------------------------------------------------------------------------- // // Function: SetDaclForDsObject // Synopsis: Sets the the DACL for the specified DS object // // Arguments: [IN pDsObject] -- ds object // [IN pDACL] --pointer to dacl to be set // //---------------------------------------------------------------------------- inline HRESULT SetDaclForDsObject( IDirectoryObject* pDsObject, PACL pDACL ) { if(!pDsObject || !pDACL) return E_POINTER; WCHAR const c_szSDProperty[] = L"nTSecurityDescriptor"; PSECURITY_DESCRIPTOR pSD = NULL; PSECURITY_DESCRIPTOR pSDCurrent = NULL; HRESULT hr = S_OK; //Get the current SD for the object hr = GetSDForDsObject(pDsObject,NULL,&pSDCurrent); //Get the control for the current security descriptor SECURITY_DESCRIPTOR_CONTROL currentControl; DWORD dwRevision = 0; if( SUCCEEDED(hr) ) { if( !GetSecurityDescriptorControl(pSDCurrent, ¤tControl, &dwRevision) ) { DWORD dwErr = GetLastError(); hr = HRESULT_FROM_WIN32(dwErr); } } if( SUCCEEDED(hr) ) { //Allocate the buffer for Security Descriptor pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH + pDACL->AclSize); if(!pSD) { hr = E_OUTOFMEMORY; } } if( SUCCEEDED(hr) ) { if(!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) { DWORD dwErr = GetLastError(); hr = HRESULT_FROM_WIN32(dwErr); } } if( SUCCEEDED(hr) ) { PISECURITY_DESCRIPTOR pISD = (PISECURITY_DESCRIPTOR)pSD; // // Finally, build the security descriptor // pISD->Control |= SE_DACL_PRESENT | SE_DACL_AUTO_INHERIT_REQ | (currentControl & (SE_DACL_PROTECTED | SE_DACL_AUTO_INHERITED)); if (pDACL->AclSize > 0) { pISD->Dacl = (PACL)(pISD + 1); CopyMemory(pISD->Dacl, pDACL, pDACL->AclSize); } // We are only setting DACL information hr = SetSecInfoMask(pDsObject, DACL_SECURITY_INFORMATION); } SECURITY_DESCRIPTOR_CONTROL sdControl = 0; if( SUCCEEDED(hr) ) { // // If necessary, make a self-relative copy of the security descriptor // if(!GetSecurityDescriptorControl(pSD, &sdControl, &dwRevision)) { DWORD dwErr = GetLastError(); hr = HRESULT_FROM_WIN32(dwErr); } } DWORD dwSDLength = 0; if( SUCCEEDED(hr) ) { // Need the total size dwSDLength = GetSecurityDescriptorLength(pSD); if (!(sdControl & SE_SELF_RELATIVE)) { PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, dwSDLength); if (psd == NULL || !MakeSelfRelativeSD(pSD, psd, &dwSDLength)) { DWORD dwErr = GetLastError(); hr = HRESULT_FROM_WIN32(dwErr); } // Point to the self-relative copy LocalFree(pSD); pSD = psd; } } if( SUCCEEDED(hr) ) { ADSVALUE attributeValue; attributeValue.dwType = ADSTYPE_NT_SECURITY_DESCRIPTOR; attributeValue.SecurityDescriptor.dwLength = dwSDLength; attributeValue.SecurityDescriptor.lpValue = (LPBYTE)pSD; ADS_ATTR_INFO attributeInfo; attributeInfo.pszAttrName = (LPWSTR)c_szSDProperty; attributeInfo.dwControlCode = ADS_ATTR_UPDATE; attributeInfo.dwADsType = ADSTYPE_NT_SECURITY_DESCRIPTOR; attributeInfo.pADsValues = &attributeValue; attributeInfo.dwNumValues = 1; // Write the security descriptor DWORD dwAttributesModified; hr = pDsObject->SetObjectAttributes(&attributeInfo, 1, &dwAttributesModified); } if(pSDCurrent) { LocalFree(pSDCurrent); } if(pSD) { LocalFree(pSD); } return S_OK; } inline HRESULT SetDaclForDsObjectPath( LPCWSTR pszObjectPath, PACL pDACL ) { // VAlidate the parameters if(!pszObjectPath || !pDACL) return E_POINTER; // Get the object and then pass it on to the helper function CComPtr spDsObject = NULL; HRESULT hr = ADsGetObject( pszObjectPath, IID_IDirectoryObject, (void**)&spDsObject ); if( SUCCEEDED(hr) ) { hr = SetDaclForDsObject( spDsObject, pDACL ); } return hr; } #endif // _AUSRUTIL_H