#include "nds.hxx" #pragma hdrstop FILTERS Filters[] = { {L"user", NDS_USER_ID}, {L"group", NDS_GROUP_ID}, {L"queue", NDS_PRINTER_ID}, {L"domain", NDS_DOMAIN_ID}, {L"computer", NDS_COMPUTER_ID}, {L"service", NDS_SERVICE_ID}, {L"fileservice", NDS_FILESERVICE_ID}, {L"fileshare", NDS_FILESHARE_ID}, {L"class", NDS_CLASS_ID}, {L"functionalset", NDS_FUNCTIONALSET_ID}, {L"syntax", NDS_SYNTAX_ID}, {L"property", NDS_PROPERTY_ID}, {L"tree", NDS_TREE_ID}, {L"Organizational Unit", NDS_OU_ID}, {L"Organization", NDS_O_ID}, {L"Locality", NDS_LOCALITY_ID} }; #define MAX_FILTERS (sizeof(Filters)/sizeof(FILTERS)) PFILTERS gpFilters = Filters; DWORD gdwMaxFilters = MAX_FILTERS; extern WCHAR * szProviderName; //+------------------------------------------------------------------------ // // Class: Common // // Purpose: Contains Winnt routines and properties that are common to // all Winnt objects. Winnt objects get the routines and // properties through C++ inheritance. // //------------------------------------------------------------------------- HRESULT BuildADsPath( BSTR Parent, BSTR Name, BSTR *pADsPath ) { LPWSTR lpADsPath = NULL; WCHAR ProviderName[MAX_PATH]; HRESULT hr = S_OK; DWORD dwLen = 0; LPWSTR pszDisplayName = NULL; // // We will assert if bad parameters are passed to us. // This is because this should never be the case. This // is an internal call // ADsAssert(Parent && Name); ADsAssert(pADsPath); if ((!Name) || (!Parent) || (!pADsPath)) { BAIL_ON_FAILURE(hr = E_INVALIDARG); } // // Get the display name for the name; The display name will have the proper // escaping for characters that have special meaning in an ADsPath like // '/' etc. // hr = GetDisplayName( Name, &pszDisplayName ); BAIL_ON_FAILURE(hr); // // Special case the Namespace object; if // the parent is L"ADs:", then Name = ADsPath // if (!_wcsicmp(Parent, L"ADs:")) { hr = ADsAllocString( pszDisplayName, pADsPath); BAIL_ON_FAILURE(hr); goto cleanup; } // // Allocate the right side buffer // 2 for // + a buffer of MAX_PATH // dwLen = wcslen(Parent) + wcslen(pszDisplayName) + 2 + MAX_PATH; lpADsPath = (LPWSTR)AllocADsMem(dwLen*sizeof(WCHAR)); if (!lpADsPath) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } // // The rest of the cases we expect valid data, // Path, Parent and Name are read-only, the end-user // cannot modify this data // // // For the first object, the domain object we do not add // the first backslash; so we examine that the parent is // L"WinNT:" and skip the slash otherwise we start with // the slash // wsprintf(ProviderName, L"%s:", szProviderName); wcscpy(lpADsPath, Parent); if (_wcsicmp(lpADsPath, ProviderName)) { wcscat(lpADsPath, L"/"); }else { wcscat(lpADsPath, L"//"); } wcscat(lpADsPath, pszDisplayName); hr = ADsAllocString( lpADsPath, pADsPath); cleanup: error: if (lpADsPath) { FreeADsMem(lpADsPath); } if (pszDisplayName) { FreeADsMem(pszDisplayName); } RRETURN(hr); } HRESULT BuildSchemaPath( BSTR bstrADsPath, BSTR bstrClass, BSTR *pSchemaPath ) { WCHAR ADsSchema[MAX_PATH]; OBJECTINFO ObjectInfo; POBJECTINFO pObjectInfo = &ObjectInfo; CLexer Lexer(bstrADsPath); HRESULT hr = S_OK; memset(pObjectInfo, 0, sizeof(OBJECTINFO)); wcscpy(ADsSchema, L""); memset(pObjectInfo, 0, sizeof(OBJECTINFO)); if (bstrClass && *bstrClass) { hr = ADsObject(&Lexer, pObjectInfo); BAIL_ON_FAILURE(hr); if (pObjectInfo->TreeName) { wsprintf(ADsSchema,L"%s://",pObjectInfo->ProviderName); wcscat(ADsSchema, pObjectInfo->TreeName); wcscat(ADsSchema,L"/schema/"); wcscat(ADsSchema, bstrClass); } } hr = ADsAllocString( ADsSchema, pSchemaPath); error: if (pObjectInfo) { FreeObjectInfo( pObjectInfo ); } RRETURN(hr); } HRESULT BuildADsGuid( REFCLSID clsid, BSTR *pADsClass ) { WCHAR ADsClass[MAX_PATH]; if (!StringFromGUID2(clsid, ADsClass, MAX_PATH)) { // // MAX_PATH should be more than enough for the GUID. // ADsAssert(!"GUID too big !!!"); RRETURN(E_FAIL); } RRETURN(ADsAllocString( ADsClass, pADsClass)); } HRESULT MakeUncName( LPWSTR szSrcBuffer, LPWSTR szTargBuffer ) { ADsAssert(szSrcBuffer && *szSrcBuffer); wcscpy(szTargBuffer, L"\\\\"); wcscat(szTargBuffer, szSrcBuffer); RRETURN(S_OK); } HRESULT ValidateOutParameter( BSTR * retval ) { if (!retval) { RRETURN(E_ADS_BAD_PARAMETER); } RRETURN(S_OK); } PKEYDATA CreateTokenList( LPWSTR pKeyData, WCHAR ch ) { DWORD cTokens; DWORD cb; PKEYDATA pResult; LPWSTR pDest; LPWSTR psz = pKeyData; LPWSTR *ppToken; WCHAR szTokenList[MAX_PATH]; if (!psz || !*psz) return NULL; wsprintf(szTokenList, L"%c", ch); cTokens=1; // Scan through the string looking for commas, // ensuring that each is followed by a non-NULL character: while ((psz = wcschr(psz, ch)) && psz[1]) { cTokens++; psz++; } cb = sizeof(KEYDATA) + (cTokens-1) * sizeof(LPWSTR) + wcslen(pKeyData)*sizeof(WCHAR) + sizeof(WCHAR); if (!(pResult = (PKEYDATA)AllocADsMem(cb))) return NULL; // Initialise pDest to point beyond the token pointers: pDest = (LPWSTR)((LPBYTE)pResult + sizeof(KEYDATA) + (cTokens-1) * sizeof(LPWSTR)); // Then copy the key data buffer there: wcscpy(pDest, pKeyData); ppToken = pResult->pTokens; // Remember, wcstok has the side effect of replacing the delimiter // by NULL, which is precisely what we want: psz = wcstok (pDest, szTokenList); while (psz) { *ppToken++ = psz; psz = wcstok (NULL, szTokenList); } pResult->cTokens = cTokens; return( pResult ); } DWORD ADsNwNdsOpenObject( IN LPWSTR ObjectDN, IN CCredentials& Credentials, OUT HANDLE * lphObject, OUT LPWSTR lpObjectFullName OPTIONAL, OUT LPWSTR lpObjectClassName OPTIONAL, OUT LPDWORD lpdwModificationTime, OUT LPDWORD lpdwSubordinateCount OPTIONAL ) { HRESULT hr = S_OK; DWORD dwStatus; LPWSTR pszUserName = NULL; LPWSTR pszPassword = NULL; hr = Credentials.GetUserName(&pszUserName); hr = Credentials.GetPassword(&pszPassword); dwStatus = NwNdsOpenObject( ObjectDN, pszUserName, pszPassword, lphObject, NULL, // szObjectName optional parameter lpObjectFullName, lpObjectClassName, lpdwModificationTime, lpdwSubordinateCount ); if (pszUserName) { FreeADsStr(pszUserName); } if (pszPassword) { SecureZeroMemory(pszPassword, wcslen(pszPassword)*sizeof(WCHAR)); FreeADsStr(pszPassword); } return(dwStatus); } HRESULT CheckAndSetExtendedError( DWORD dwRetval ) { DWORD dwLastError; WCHAR pszErrorString[MAX_PATH]; WCHAR pszProviderName[MAX_PATH]; INT numChars; HRESULT hr =S_OK; wcscpy(pszErrorString, L""); wcscpy(pszProviderName, L""); if (dwRetval == NDS_ERR_SUCCESS){ hr = S_OK; } else { dwLastError = GetLastError(); hr = HRESULT_FROM_WIN32(dwLastError); if (dwLastError == ERROR_EXTENDED_ERROR){ numChars = LoadString( g_hInst, dwRetval, pszErrorString, MAX_PATH-1); numChars = LoadString( g_hInst, NDS_PROVIDER_ID, pszProviderName, MAX_PATH -1); ADsSetLastError( dwRetval, pszErrorString, pszProviderName ); } } RRETURN(hr); } HRESULT CopyObject( IN LPWSTR pszSrcADsPath, IN LPWSTR pszDestContainer, IN LPWSTR pszCommonName, //optional IN CCredentials Credentials, OUT VOID ** ppObject ) { // // this function is a wrapper for the copy functionality which is used // by both IADsContainer::CopyHere and IADsContainer::MoveHere // HRESULT hr = S_OK; DWORD dwStatus = 0L; LPWSTR pszNDSSrcName = NULL; LPWSTR pszNDSParentName = NULL; HANDLE hSrcOperationData = NULL; HANDLE hSrcObject = NULL; HANDLE hDestOperationData = NULL; HANDLE hDestObject = NULL; HANDLE hAttrOperationData = NULL; DWORD dwNumEntries = 0L; LPNDS_ATTR_INFO lpEntries = NULL; LPWSTR pszObjectFullName= NULL; LPWSTR pszObjectClassName= NULL; LPWSTR pszParent= NULL; LPWSTR pszRelativeName = NULL; LPWSTR pszCN = NULL; DWORD i = 0; DWORD dwInfoType; LPNDS_ATTR_DEF lpAttrDef = NULL; IADs *pADs = NULL; // // allocate all variables that are needed // pszObjectFullName = (LPWSTR)AllocADsMem(MAX_PATH* sizeof(WCHAR)); if (!pszObjectFullName){ hr = E_OUTOFMEMORY; goto error; } pszObjectClassName = (LPWSTR)AllocADsMem(MAX_PATH* sizeof(WCHAR)); if (!pszObjectClassName){ hr = E_OUTOFMEMORY; goto error; } pszParent = (LPWSTR)AllocADsMem(MAX_PATH* sizeof(WCHAR)); if (!pszParent){ hr = E_OUTOFMEMORY; goto error; } pszCN = (LPWSTR)AllocADsMem(MAX_PATH* sizeof(WCHAR)); if (!pszCN){ hr = E_OUTOFMEMORY; goto error; } hr = BuildNDSPathFromADsPath( pszSrcADsPath, &pszNDSSrcName ); BAIL_ON_FAILURE(hr); hr = BuildADsParentPath( pszSrcADsPath, pszParent, pszCN ); BAIL_ON_FAILURE(hr); dwStatus = ADsNwNdsOpenObject( pszNDSSrcName, Credentials, &hSrcObject, pszObjectFullName, pszObjectClassName, NULL, NULL ); CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr); dwStatus = NwNdsReadObject( hSrcObject, NDS_INFO_ATTR_NAMES_VALUES, &hSrcOperationData ); CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr); dwStatus = NwNdsGetAttrListFromBuffer( hSrcOperationData, &dwNumEntries, &lpEntries ); CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr); // // we have now extracted all the information we need from the source // object, we need to add this information to the destination object // as attributes and values // // // create the destination object // hr = BuildNDSPathFromADsPath( pszDestContainer, &pszNDSParentName ); BAIL_ON_FAILURE(hr); dwStatus = ADsNwNdsOpenObject( pszNDSParentName, Credentials, &hDestObject, NULL, NULL, NULL, NULL ); CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr); // // use the name given by the user if given at all // otherwise use the name of the source // if ( pszCommonName != NULL) { pszRelativeName = pszCommonName; } else { pszRelativeName = pszCN; } dwStatus = NwNdsCreateBuffer( NDS_OBJECT_ADD, &hDestOperationData ); CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr); // // take each of these entries and get back their schema // attribute definitions. the same handle to the DestObject // can be used to open the schema // dwStatus = NwNdsCreateBuffer( NDS_SCHEMA_READ_ATTR_DEF, &hAttrOperationData ); CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr); for(i=0; i< dwNumEntries; i++){ dwStatus = NwNdsPutInBuffer( lpEntries[i].szAttributeName, 0, NULL, 0, 0, hAttrOperationData ); CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr); } dwStatus = NwNdsReadAttrDef( hDestObject, NDS_INFO_NAMES_DEFS, & hAttrOperationData ); CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr); dwStatus = NwNdsGetAttrDefListFromBuffer( hAttrOperationData, & dwNumEntries, & dwInfoType, (void **)& lpAttrDef ); CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr); for (i=0; i< dwNumEntries; i++){ if(wcscmp(lpEntries[i].szAttributeName, ACL_name) == 0){ // // skip this attribute. Let it default // continue; } if(wcscmp(lpEntries[i].szAttributeName, OBJECT_CLASS_name) == 0){ dwStatus = NwNdsPutInBuffer( lpEntries[i].szAttributeName, lpEntries[i].dwSyntaxId, lpEntries[i].lpValue, 1, // only the first value is relevant NDS_ATTR_ADD, hDestOperationData ); } else if ( (lpAttrDef[i].dwFlags & NDS_READ_ONLY_ATTR) || (lpAttrDef[i].dwFlags & NDS_HIDDEN_ATTR) ){ // // skip this value // continue; } else { dwStatus = NwNdsPutInBuffer( lpEntries[i].szAttributeName, lpEntries[i].dwSyntaxId, lpEntries[i].lpValue, lpEntries[i].dwNumberOfValues, NDS_ATTR_ADD, hDestOperationData ); } } CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr); dwStatus = NwNdsAddObject( hDestObject, pszRelativeName, hDestOperationData ); CHECK_AND_SET_EXTENDED_ERROR(dwStatus, hr); hr = CNDSGenObject::CreateGenericObject( pszDestContainer, pszRelativeName, pszObjectClassName, Credentials, ADS_OBJECT_BOUND, IID_IADs, (void **)&pADs ); BAIL_ON_FAILURE(hr); // // InstantiateDerivedObject should add-ref this pointer for us. // hr = InstantiateDerivedObject( pADs, Credentials, IID_IUnknown, ppObject ); if (FAILED(hr)) { hr = pADs->QueryInterface( IID_IUnknown, ppObject ); BAIL_ON_FAILURE(hr); } error: if (pszObjectFullName){ FreeADsMem(pszObjectFullName); } if (pszObjectClassName){ FreeADsMem(pszObjectClassName); } if (pszParent){ FreeADsMem(pszParent); } if (pszCN){ FreeADsMem(pszCN); } if (pszNDSSrcName) { FreeADsStr(pszNDSSrcName); } if (pszNDSParentName) { FreeADsStr(pszNDSParentName); } if(hSrcOperationData){ dwStatus = NwNdsFreeBuffer(hSrcOperationData); } if(hSrcObject){ dwStatus = NwNdsCloseObject(hSrcObject); } if(hDestOperationData){ dwStatus = NwNdsFreeBuffer(hDestOperationData); } if(hDestObject){ dwStatus = NwNdsCloseObject(hDestObject); } if(hAttrOperationData){ dwStatus = NwNdsFreeBuffer(hAttrOperationData); } if (pADs){ pADs->Release(); } RRETURN(hr); } HRESULT ConvertDWORDtoSYSTEMTIME( DWORD dwDate, LPSYSTEMTIME pSystemTime ) { FILETIME fileTime; LARGE_INTEGER tmpTime; HRESULT hr = S_OK; ::RtlSecondsSince1970ToTime(dwDate, &tmpTime ); fileTime.dwLowDateTime = tmpTime.LowPart; fileTime.dwHighDateTime = tmpTime.HighPart; if (!FileTimeToSystemTime( &fileTime, pSystemTime)){ hr = HRESULT_FROM_WIN32(GetLastError()); } RRETURN(hr); } HRESULT ConvertSYSTEMTIMEtoDWORD( CONST SYSTEMTIME *pSystemTime, DWORD *pdwDate ) { FILETIME fileTime; LARGE_INTEGER tmpTime; HRESULT hr = S_OK; if (!SystemTimeToFileTime(pSystemTime,&fileTime)) { hr = HRESULT_FROM_WIN32(GetLastError()); BAIL_ON_FAILURE(hr); } tmpTime.LowPart = fileTime.dwLowDateTime; tmpTime.HighPart = fileTime.dwHighDateTime; ::RtlTimeToSecondsSince1970(&tmpTime, (ULONG *)pdwDate); error: RRETURN(hr); }