#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; struct _err_lookup_ { LPWSTR errString; int errNo; } g_aErrLookup[] = { {L"ERR_INSUFFICIENT_MEMORY ", -150 }, {L"ERR_REQUEST_UNKNOWN ", -251 }, {L"ERR_OF_SOME_SORT ", -255 }, {L"ERR_NOT_ENOUGH_MEMORY ", -301 }, {L"ERR_BAD_KEY ", -302 }, {L"ERR_BAD_CONTEXT ", -303 }, {L"ERR_BUFFER_FULL ", -304 }, {L"ERR_LIST_EMPTY ", -305 }, {L"ERR_BAD_SYNTAX ", -306 }, {L"ERR_BUFFER_EMPTY ", -307 }, {L"ERR_BAD_VERB ", -308 }, {L"ERR_EXPECTED_IDENTIFIER ", -309 }, {L"ERR_EXPECTED_EQUALS ", -310 }, {L"ERR_ATTR_TYPE_EXPECTED ", -311 }, {L"ERR_ATTR_TYPE_NOT_EXPECTED ", -312 }, {L"ERR_FILTER_TREE_EMPTY ", -313 }, {L"ERR_INVALID_OBJECT_NAME ", -314 }, {L"ERR_EXPECTED_RDN_DELIMITER ", -315 }, {L"ERR_TOO_MANY_TOKENS ", -316 }, {L"ERR_INCONSISTENT_MULTIAVA ", -317 }, {L"ERR_COUNTRY_NAME_TOO_LONG ", -318 }, {L"ERR_SYSTEM_ERROR ", -319 }, {L"ERR_CANT_ADD_ROOT ", -320 }, {L"ERR_UNABLE_TO_ATTACH ", -321 }, {L"ERR_INVALID_HANDLE ", -322 }, {L"ERR_BUFFER_ZERO_LENGTH ", -323 }, {L"ERR_INVALID_REPLICA_TYPE ", -324 }, {L"ERR_INVALID_ATTR_SYNTAX ", -325 }, {L"ERR_INVALID_FILTER_SYNTAX ", -326 }, {L"ERR_CONTEXT_CREATION ", -328 }, {L"ERR_INVALID_UNION_TAG ", -329 }, {L"ERR_INVALID_SERVER_RESPONSE ", -330 }, {L"ERR_NULL_POINTER ", -331 }, {L"ERR_NO_SERVER_FOUND ", -332 }, {L"ERR_NO_CONNECTION ", -333 }, {L"ERR_RDN_TOO_LONG ", -334 }, {L"ERR_DUPLICATE_TYPE ", -335 }, {L"ERR_DATA_STORE_FAILURE ", -336 }, {L"ERR_NOT_LOGGED_IN ", -337 }, {L"ERR_INVALID_PASSWORD_CHARS ", -338 }, {L"ERR_FAILED_SERVER_AUTHENT ", -339 }, {L"ERR_TRANSPORT ", -340 }, {L"ERR_NO_SUCH_SYNTAX ", -341 }, {L"ERR_INVALID_DS_NAME ", -342 }, {L"ERR_ATTR_NAME_TOO_LONG ", -343 }, {L"ERR_INVALID_TDS ", -344 }, {L"ERR_INVALID_DS_VERSION ", -345 }, {L"ERR_UNICODE_TRANSLATION ", -346 }, {L"ERR_SCHEMA_NAME_TOO_LONG ", -347 }, {L"ERR_UNICODE_FILE_NOT_FOUND ", -348 }, {L"ERR_UNICODE_ALREADY_LOADED ", -349 }, {L"ERR_NOT_CONTEXT_OWNER ", -350 }, {L"ERR_ATTEMPT_TO_AUTHENTICATE_0 ", -351 }, {L"ERR_NO_WRITABLE_REPLICAS ", -352 }, {L"ERR_DN_TOO_LONG ", -353 }, {L"ERR_RENAME_NOT_ALLOWED ", -354 }, {L"ERR_NO_SUCH_ENTRY ", -601 }, {L"ERR_NO_SUCH_VALUE ", -602 }, {L"ERR_NO_SUCH_ATTRIBUTE ", -603 }, {L"ERR_NO_SUCH_CLASS ", -604 }, {L"ERR_NO_SUCH_PARTITION ", -605 }, {L"ERR_ENTRY_ALREADY_EXISTS ", -606 }, {L"ERR_NOT_EFFECTIVE_CLASS ", -607 }, {L"ERR_ILLEGAL_ATTRIBUTE ", -608 }, {L"ERR_MISSING_MANDATORY ", -609 }, {L"ERR_ILLEGAL_DS_NAME ", -610 }, {L"ERR_ILLEGAL_CONTAINMENT ", -611 }, {L"ERR_CANT_HAVE_MULTIPLE_VALUES ", -612 }, {L"ERR_SYNTAX_VIOLATION ", -613 }, {L"ERR_DUPLICATE_VALUE ", -614 }, {L"ERR_ATTRIBUTE_ALREADY_EXISTS ", -615 }, {L"ERR_MAXIMUM_ENTRIES_EXIST ", -616 }, {L"ERR_DATABASE_FORMAT ", -617 }, {L"ERR_INCONSISTENT_DATABASE ", -618 }, {L"ERR_INVALID_COMPARISON ", -619 }, {L"ERR_COMPARISON_FAILED ", -620 }, {L"ERR_TRANSACTIONS_DISABLED ", -621 }, {L"ERR_INVALID_TRANSPORT ", -622 }, {L"ERR_SYNTAX_INVALID_IN_NAME ", -623 }, {L"ERR_REPLICA_ALREADY_EXISTS ", -624 }, {L"ERR_TRANSPORT_FAILURE ", -625 }, {L"ERR_ALL_REFERRALS_FAILED ", -626 }, {L"ERR_CANT_REMOVE_NAMING_VALUE ", -627 }, {L"ERR_OBJECT_CLASS_VIOLATION ", -628 }, {L"ERR_ENTRY_IS_NOT_LEAF ", -629 }, {L"ERR_DIFFERENT_TREE ", -630 }, {L"ERR_ILLEGAL_REPLICA_TYPE ", -631 }, {L"ERR_SYSTEM_FAILURE ", -632 }, {L"ERR_INVALID_ENTRY_FOR_ROOT ", -633 }, {L"ERR_NO_REFERRALS ", -634 }, {L"ERR_REMOTE_FAILURE ", -635 }, {L"ERR_UNREACHABLE_SERVER ", -636 }, {L"ERR_PREVIOUS_MOVE_IN_PROGRESS ", -637 }, {L"ERR_NO_CHARACTER_MAPPING ", -638 }, {L"ERR_INCOMPLETE_AUTHENTICATION ", -639 }, {L"ERR_INVALID_CERTIFICATE ", -640 }, {L"ERR_INVALID_REQUEST ", -641 }, {L"ERR_INVALID_ITERATION ", -642 }, {L"ERR_SCHEMA_IS_NONREMOVABLE ", -643 }, {L"ERR_SCHEMA_IS_IN_USE ", -644 }, {L"ERR_CLASS_ALREADY_EXISTS ", -645 }, {L"ERR_BAD_NAMING_ATTRIBUTES ", -646 }, {L"ERR_NOT_ROOT_PARTITION ", -647 }, {L"ERR_INSUFFICIENT_STACK ", -648 }, {L"ERR_INSUFFICIENT_BUFFER ", -649 }, {L"ERR_AMBIGUOUS_CONTAINMENT ", -650 }, {L"ERR_AMBIGUOUS_NAMING ", -651 }, {L"ERR_DUPLICATE_MANDATORY ", -652 }, {L"ERR_DUPLICATE_OPTIONAL ", -653 }, {L"ERR_PARTITION_BUSY ", -654 }, {L"ERR_MULTIPLE_REPLICAS ", -655 }, {L"ERR_CRUCIAL_REPLICA ", -656 }, {L"ERR_SCHEMA_SYNC_IN_PROGRESS ", -657 }, {L"ERR_SKULK_IN_PROGRESS ", -658 }, {L"ERR_TIME_NOT_SYNCHRONIZED ", -659 }, {L"ERR_RECORD_IN_USE ", -660 }, {L"ERR_DS_VOLUME_NOT_MOUNTED ", -661 }, {L"ERR_DS_VOLUME_IO_FAILURE ", -662 }, {L"ERR_DS_LOCKED ", -663 }, {L"ERR_OLD_EPOCH ", -664 }, {L"ERR_NEW_EPOCH ", -665 }, {L"ERR_INCOMPATIBLE_DS_VERSION ", -666 }, {L"ERR_PARTITION_ROOT ", -667 }, {L"ERR_ENTRY_NOT_CONTAINER ", -668 }, {L"ERR_FAILED_AUTHENTICATION ", -669 }, {L"ERR_INVALID_CONTEXT ", -670 }, {L"ERR_NO_SUCH_PARENT ", -671 }, {L"ERR_NO_ACCESS ", -672 }, {L"ERR_REPLICA_NOT_ON ", -673 }, {L"ERR_INVALID_NAME_SERVICE ", -674 }, {L"ERR_INVALID_TASK ", -675 }, {L"ERR_INVALID_CONN_HANDLE ", -676 }, {L"ERR_INVALID_IDENTITY ", -677 }, {L"ERR_DUPLICATE_ACL ", -678 }, {L"ERR_PARTITION_ALREADY_EXISTS ", -679 }, {L"ERR_TRANSPORT_MODIFIED ", -680 }, {L"ERR_ALIAS_OF_AN_ALIAS ", -681 }, {L"ERR_AUDITING_FAILED ", -682 }, {L"ERR_INVALID_API_VERSION ", -683 }, {L"ERR_SECURE_NCP_VIOLATION ", -684 }, {L"ERR_MOVE_IN_PROGRESS ", -685 }, {L"ERR_NOT_LEAF_PARTITION ", -686 }, {L"ERR_CANNOT_ABORT ", -687 }, {L"ERR_CACHE_OVERFLOW ", -688 }, {L"ERR_INVALID_SUBORDINATE_COUNT ", -689 }, {L"ERR_INVALID_RDN ", -690 }, {L"ERR_MOD_TIME_NOT_CURRENT ", -691 }, {L"ERR_INCORRECT_BASE_CLASS ", -692 }, {L"ERR_MISSING_REFERENCE ", -693 }, {L"ERR_LOST_ENTRY ", -694 }, {L"ERR_AGENT_ALREADY_REGISTERED ", -695 }, {L"ERR_DS_LOADER_BUSY ", -696 }, {L"ERR_DS_CANNOT_RELOAD ", -697 }, {L"ERR_REPLICA_IN_SKULK ", -698 }, {L"ERR_FATAL ", -699 }, {L"ERR_OBSOLETE_API ", -700 }, {L"ERR_SYNCHRONIZATION_DISABLED ", -701 }, {L"ERR_INVALID_PARAMETER ", -702 }, {L"ERR_DUPLICATE_TEMPLATE ", -703 }, {L"ERR_NO_MASTER_REPLICA ", -704 }, {L"ERR_DUPLICATE_CONTAINMENT ", -705 }, {L"ERR_NOT_SIBLING ", -706 }, {L"ERR_INVALID_SIGNATURE ", -707 }, {L"ERR_INVALID_RESPONSE ", -708 }, {L"ERR_INSUFFICIENT_SOCKETS ", -709 }, {L"ERR_DATABASE_READ_FAIL ", -710 }, {L"ERR_INVALID_CODE_PAGE ", -711 }, {L"ERR_INVALID_ESCAPE_CHAR ", -712 }, {L"ERR_INVALID_DELIMITERS ", -713 }, {L"ERR_NOT_IMPLEMENTED ", -714 }, {L"ERR_CHECKSUM_FAILURE ", -715 }, {L"ERR_CHECKSUMMING_NOT_SUPPORTED ", -716 }, {L"ERR_CRC_FAILURE ", -717 } }; DWORD g_cErrLookup = sizeof(g_aErrLookup)/sizeof(g_aErrLookup[0]); //+------------------------------------------------------------------------ // // 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); // // 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 ) { BOOL fQuoteMode = FALSE; // TRUE means we're processing between // quotation marks BOOL fEscaped = FALSE; // TRUE means next one char to be // processed should be treated as literal DWORD cTokens; DWORD cb; PKEYDATA pResult; LPWSTR pDest; LPWSTR psz = pKeyData; LPWSTR pszTokenStart = NULL; LPWSTR *ppToken; if (!psz || !*psz) return NULL; cTokens=1; // Scan through the string looking for delimiters, // ensuring that each is followed by a non-NULL character: // If this char follows an unescaped backslash: // Treat as literal, treat next char regularly (set fEscaped = FALSE) // Else, if we're between quotation marks: // If we see a quotation mark, leave quote mode // Else, treat as literal // Else, if we're not between quote marks, and we see a quote mark: // Enter quote mode // Else, if we see a backslash (and we're not already in escape or quote // mode: // Treat next char as literal (set fEscaped = TRUE) // Else, if we see the delimiter, and the next char is non-NULL: // *** Found end of a token --- Increment count of tokens *** // Else: // Do nothing, just a plain old character // Go on to next character, and repeat // // Backslashes inside quotation marks are always treated as literals, // since that is the definition of being inside quotation marks while (*psz) { if (fEscaped) { fEscaped = FALSE; } else if (fQuoteMode) { if (*psz == L'"') { fQuoteMode = FALSE; } // else, do nothing, no delimiter since in quote mode } else if (*psz == L'"') { fQuoteMode = TRUE; } else if (*psz == L'\\') { fEscaped = TRUE; } else if ( (*psz == ch) && (*(psz+1))) { cTokens++; } // else, do nothing, just a regular character 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; // Split into tokens at each delimiter be replacing the delimiter // with a NULL psz = pDest; pszTokenStart = pDest; fEscaped = FALSE; fQuoteMode = FALSE; while (*psz) { if (fEscaped) { fEscaped = FALSE; } else if (fQuoteMode) { if (*psz == L'"') { fQuoteMode = FALSE; } // else, do nothing, no delimiter since in quote mode } else if (*psz == L'"') { fQuoteMode = TRUE; } else if (*psz == L'\\') { fEscaped = TRUE; } else if ((*psz == ch) && (*(psz+1))) { *psz = '\0'; *ppToken++ = pszTokenStart; pszTokenStart = psz + 1; } // else, do nothing, just a regular character psz++; } *ppToken = pszTokenStart; pResult->cTokens = cTokens; return( pResult ); } HRESULT NDSConvertDWORDtoDATE( DWORD dwDate, DATE * pdaDate ) { FILETIME fileTime; LARGE_INTEGER tmpTime; WORD wFatDate; WORD wFatTime; HRESULT hr = S_OK; ::RtlSecondsSince1970ToTime(dwDate, &tmpTime ); fileTime.dwLowDateTime = tmpTime.LowPart; fileTime.dwHighDateTime = tmpTime.HighPart; if (!FileTimeToDosDateTime( &fileTime, &wFatDate, &wFatTime)){ hr = HRESULT_FROM_WIN32(GetLastError()); BAIL_ON_FAILURE(hr); } if (!DosDateTimeToVariantTime(wFatDate, wFatTime, pdaDate)){ hr = HRESULT_FROM_WIN32(GetLastError()); BAIL_ON_FAILURE(hr); } error: RRETURN(hr); } HRESULT NDSConvertDATEtoDWORD( DATE daDate, DWORD *pdwDate ) { FILETIME fileTime; LARGE_INTEGER tmpTime; WORD wFatDate; WORD wFatTime; HRESULT hr = S_OK; if(!VariantTimeToDosDateTime(daDate, &wFatDate, &wFatTime)){ hr = HRESULT_FROM_WIN32(GetLastError()); BAIL_ON_FAILURE(hr); } if (!DosDateTimeToFileTime(wFatDate, wFatTime, &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); } 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 = S_OK; 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) { FreeADsStr(pszPassword); } return(dwStatus); } HRESULT CheckAndSetExtendedError( DWORD dwRetval ) { DWORD dwLastError; WCHAR pszError[MAX_PATH]; WCHAR pszProviderName[MAX_PATH]; INT numChars; HRESULT hr =S_OK; wcscpy(pszError, L""); wcscpy(pszProviderName, L""); if (NWCCODE_SUCCEEDED(dwRetval)){ hr = S_OK; } else { if (dwRetval == ERR_NO_ACCESS) { hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED); } else if (dwRetval == ERR_ENTRY_ALREADY_EXISTS) { hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS); } else if (dwRetval == ERR_NO_SUCH_ENTRY) { hr = HRESULT_FROM_WIN32(ERROR_BAD_NETPATH); } else { hr = HRESULT_FROM_WIN32(ERROR_EXTENDED_ERROR); numChars = LoadString( g_hInst, NWNDS_PROVIDER_ID, pszProviderName, MAX_PATH -1); // // Set the default error string wsprintf (pszError, L"NDS ccode = %x", dwRetval); for (DWORD i=0; i < g_cErrLookup; i++ ) { if ((DWORD) g_aErrLookup[i].errNo == dwRetval) { wcscat (pszError, L"; "); wcscat (pszError, g_aErrLookup[i].errString); break; } } ADsSetLastError( dwRetval, pszError, pszProviderName ); } } RRETURN(hr); } HRESULT CopyObject( IN NDS_CONTEXT_HANDLE hDestADsContext, IN LPWSTR pszSrcADsPath, IN LPWSTR pszDestContainer, IN LPWSTR pszCommonName, //optional IN CCredentials& Credentials, OUT VOID ** ppObject ) { HRESULT hr = S_OK; LPWSTR pszSrcNDSTreeName = NULL, pszSrcNDSDn = NULL; LPWSTR pszChildNDSTreeName = NULL, pszChildNDSDn = NULL; NDS_CONTEXT_HANDLE hSrcADsContext = NULL; BSTR bstrChildADsPath = NULL; NDS_BUFFER_HANDLE hDestOperationData = NULL; NDS_BUFFER_HANDLE hAttrOperationData = NULL; LPWSTR pszObjectClassName = NULL; DWORD dwNumEntries = 0L; DWORD dwNumEntriesDefs = 0L; LPNDS_ATTR_INFO lpEntries = NULL; LPWSTR pszParent= NULL; LPWSTR pszRelativeName = NULL; LPWSTR pszCN = NULL; DWORD i = 0; DWORD dwInfoType; LPNDS_ATTR_DEF lpAttrDef = NULL; IADs *pADs = NULL; LPWSTR *ppszAttrs = NULL; // // allocate all variables that are needed // 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 = BuildADsParentPath( pszSrcADsPath, pszParent, pszCN ); BAIL_ON_FAILURE(hr); hr = BuildNDSPathFromADsPath2( pszSrcADsPath, &pszSrcNDSTreeName, &pszSrcNDSDn ); BAIL_ON_FAILURE(hr); hr = ADsNdsOpenContext( pszSrcNDSTreeName, Credentials, &hSrcADsContext ); BAIL_ON_FAILURE(hr); hr = ADsNdsReadObject( hSrcADsContext, pszSrcNDSDn, DS_ATTRIBUTE_VALUES, NULL, (DWORD) -1, // signifies all attributes need to be returned NULL, &lpEntries, &dwNumEntries ); BAIL_ON_FAILURE(hr); // // create the destination object // // 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; } hr = BuildADsPath( pszDestContainer, pszRelativeName, &bstrChildADsPath ); BAIL_ON_FAILURE(hr); hr = BuildNDSPathFromADsPath2( bstrChildADsPath, &pszChildNDSTreeName, &pszChildNDSDn ); BAIL_ON_FAILURE(hr); hr = ADsNdsCreateBuffer( hDestADsContext, DSV_ADD_ENTRY, &hDestOperationData ); BAIL_ON_FAILURE(hr); ppszAttrs = (LPWSTR *) AllocADsMem(sizeof(LPWSTR) * dwNumEntries); if (!ppszAttrs) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } for(i=0; i< dwNumEntries; i++) ppszAttrs[i] = lpEntries[i].szAttributeName; hr = ADsNdsReadAttrDef( hDestADsContext, DS_ATTR_DEFS, ppszAttrs, dwNumEntries, &hAttrOperationData ); BAIL_ON_FAILURE(hr); hr = ADsNdsGetAttrDefListFromBuffer( hDestADsContext, hAttrOperationData, &dwNumEntriesDefs, &dwInfoType, & lpAttrDef ); BAIL_ON_FAILURE(hr); for (i=0; i< dwNumEntriesDefs; 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){ hr = ADsNdsPutInBuffer( hDestADsContext, hDestOperationData, lpEntries[i].szAttributeName, lpEntries[i].dwSyntaxId, lpEntries[i].lpValue, 1, DS_ADD_ATTRIBUTE ); BAIL_ON_FAILURE(hr); pszObjectClassName = lpEntries[i].lpValue ? lpEntries[i].lpValue[0].NdsValue.value_20.ClassName : NULL; } else if ( (lpAttrDef[i].dwFlags & DS_READ_ONLY_ATTR) || (lpAttrDef[i].dwFlags & DS_HIDDEN_ATTR) ){ // // skip this value // continue; } else { hr = ADsNdsPutInBuffer( hDestADsContext, hDestOperationData, lpEntries[i].szAttributeName, lpEntries[i].dwSyntaxId, lpEntries[i].lpValue, lpEntries[i].dwNumberOfValues, DS_ADD_ATTRIBUTE ); BAIL_ON_FAILURE(hr); } } hr = ADsNdsAddObject( hDestADsContext, pszChildNDSDn, hDestOperationData ); BAIL_ON_FAILURE(hr); if (!pszObjectClassName) { BAIL_ON_FAILURE(hr = E_FAIL); } if (_wcsicmp(pszObjectClassName, L"user") == 0) { hr = ADsNdsGenObjectKey(hDestADsContext, pszChildNDSDn); BAIL_ON_FAILURE(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: FreeADsMem(pszParent); FreeADsMem(pszCN); FreeADsStr(pszSrcNDSTreeName); FreeADsStr(pszSrcNDSDn); FreeADsStr(pszChildNDSTreeName); FreeADsStr(pszChildNDSDn); FreeADsMem(ppszAttrs); if (bstrChildADsPath) { SysFreeString(bstrChildADsPath); } if (hDestOperationData) { ADsNdsFreeBuffer(hDestOperationData); } if (hAttrOperationData) { ADsNdsFreeBuffer(hAttrOperationData); } if(hSrcADsContext){ ADsNdsCloseContext(hSrcADsContext); } if (pADs){ pADs->Release(); } FreeNdsAttrInfo(lpEntries, dwNumEntries); ADsNdsFreeAttrDefList(lpAttrDef, dwNumEntriesDefs); RRETURN(hr); } HRESULT MoveObject( IN NDS_CONTEXT_HANDLE hDestADsContext, IN LPWSTR pszSrcADsPath, IN LPWSTR pszDestContainer, IN LPWSTR pszCommonName, //optional IN CCredentials& Credentials, OUT VOID ** ppObject ) { HRESULT hr = S_OK; LPWSTR pszSrcNDSTreeName = NULL, pszSrcNDSDn = NULL; LPWSTR pszParentNDSTreeName = NULL, pszParentNDSDn = NULL; NDS_CONTEXT_HANDLE hSrcADsContext = NULL; LPWSTR pszObjectClassName = NULL; DWORD dwNumEntries = 0L; LPNDS_ATTR_INFO lpEntries = NULL; LPWSTR pszParent= NULL; LPWSTR pszRelativeName = NULL; LPWSTR pszCN = NULL; IADs *pADs = NULL; LPWSTR pszAttrs = L"object Class"; // // allocate all variables that are needed // 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 = BuildADsParentPath( pszSrcADsPath, pszParent, pszCN ); BAIL_ON_FAILURE(hr); hr = BuildNDSPathFromADsPath2( pszSrcADsPath, &pszSrcNDSTreeName, &pszSrcNDSDn ); BAIL_ON_FAILURE(hr); hr = ADsNdsOpenContext( pszSrcNDSTreeName, Credentials, &hSrcADsContext ); BAIL_ON_FAILURE(hr); // // Just get the objectClass attribute // hr = ADsNdsReadObject( hSrcADsContext, pszSrcNDSDn, DS_ATTRIBUTE_VALUES, &pszAttrs, 1, NULL, &lpEntries, &dwNumEntries ); BAIL_ON_FAILURE(hr); if (dwNumEntries != 1) { BAIL_ON_FAILURE(hr = E_FAIL); } pszObjectClassName = (lpEntries[0].lpValue) ? lpEntries[0].lpValue[0].NdsValue.value_20.ClassName : NULL; if (!pszObjectClassName) { BAIL_ON_FAILURE(E_FAIL); } hr = BuildNDSPathFromADsPath2( pszDestContainer, &pszParentNDSTreeName, &pszParentNDSDn ); BAIL_ON_FAILURE(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; } // // If the relative name has changed and parent hasn't changed, just do a // simple rename // if ((_wcsicmp(pszParent,pszDestContainer) == 0) && (_wcsicmp(pszCN,pszRelativeName) != 0)) { hr = ADsNdsRenameObject( hDestADsContext, pszSrcNDSDn, pszRelativeName ); BAIL_ON_FAILURE(hr); } // // If the parent has changed // if (_wcsicmp(pszParent,pszDestContainer) != 0) { hr = ADsNdsMoveObject( hDestADsContext, pszSrcNDSDn, pszParentNDSDn, pszRelativeName ); BAIL_ON_FAILURE(hr); } if (!pszObjectClassName) { BAIL_ON_FAILURE(hr = E_FAIL); } 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: FreeADsMem(pszParent); FreeADsMem(pszCN); FreeADsStr(pszSrcNDSTreeName); FreeADsStr(pszSrcNDSDn); FreeADsStr(pszParentNDSTreeName); FreeADsStr(pszParentNDSDn); if(hSrcADsContext){ ADsNdsCloseContext(hSrcADsContext); } if (pADs){ pADs->Release(); } FreeNdsAttrInfo( lpEntries, dwNumEntries ); 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); } HRESULT InitializeNWLibrary( void ) { NWDSCCODE ccode; HRESULT hr = S_OK; LCONV lConvInfo; ccode = NWCallsInit(NULL, NULL); CHECK_AND_SET_EXTENDED_ERROR(ccode, hr); ccode = NWCLXInit(NULL, NULL); CHECK_AND_SET_EXTENDED_ERROR(ccode, hr); NWLlocaleconv(&lConvInfo); ccode = NWInitUnicodeTables(lConvInfo.country_id,lConvInfo.code_page); CHECK_AND_SET_EXTENDED_ERROR(ccode, hr); error: RRETURN(hr); }