//+------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1997 - 1997. // // File: idcache.cxx // // Contents: Implementation of the DS guid/name lookup cache // // History: 20-Feb-97 MacM Created // //-------------------------------------------------------------------- #include #pragma hdrstop #include #include // // This list contains pointers to memory allocated when a node is converted // to/from a guid via Rpc apis. It gets freed during cleanup. // typedef struct _ACTRL_ID_MEM { PVOID pv; BOOL fRpc; struct _ACTRL_ID_MEM *pNext; } ACTRL_ID_MEM, *PACTRL_ID_MEM; // // Global name/id cache // PACTRL_OBJ_ID_CACHE grgIdNameCache[ACTRL_OBJ_ID_TABLE_SIZE]; PACTRL_OBJ_ID_CACHE grgIdGuidCache[ACTRL_OBJ_ID_TABLE_SIZE]; // // Mem list head pointer // PACTRL_ID_MEM gpMemCleanupList; // // Last connection info/time we read from the schema // static ACTRL_ID_SCHEMA_INFO LastSchemaRead; // // Defines for attribute strings // #define ACTRL_OBJ_NAME L"NAME '" #define ACTRL_OBJ_GUID L"PROPERTY-GUID '" #define ACTRL_OBJ_CLASS L"CLASS-GUID '" #define ACTRL_OBJ_NAME_LEN sizeof(ACTRL_OBJ_NAME) / sizeof(WCHAR) - 1 #define ACTRL_OBJ_GUID_LEN sizeof(ACTRL_OBJ_GUID) / sizeof(WCHAR) - 1 #define ACTRL_OBJ_CLASS_LEN sizeof(ACTRL_OBJ_CLASS) / sizeof(WCHAR) - 1 // // Local function prototypes // PACTRL_NAME_CACHE AccctrlpLookupIdNameInCache(PWSTR pwszName); PACTRL_NAME_CACHE AccctrlpLookupGuidInCache(PSID pSid); DWORD AccctrlpNewNameGuidNode(PWSTR pwszName, PGUID pGuid, PACTRL_OBJ_ID_CACHE *ppNewNode); BOOL AccctrlpInsertIdNameNode(PACTRL_OBJ_ID_CACHE *ppRootNode, PACTRL_OBJ_ID_CACHE pNewNode); BOOL AccctrlpInsertGuidNode(PACTRL_OBJ_ID_CACHE *ppRootNode, PACTRL_OBJ_ID_CACHE pNewNode); VOID AccctrlpRemoveIdNameNode(PACTRL_OBJ_ID_CACHE *ppRootNode, PACTRL_OBJ_ID_CACHE pNewNode); VOID AccctrlpFreeUserCacheName(PWSTR pwszName, PWSTR pwszCacheName); DWORD AccctrlpLoadCacheFromSchema(PLDAP pLDAP, PWSTR pwszDsPath); static RTL_RESOURCE gIdCacheLock; BOOL bIdCacheLockInitialized = FALSE; //+---------------------------------------------------------------------------- // // Function: ActrlHashIdName // // Synopsis: Determines the hash index for the given ldap display name // // Arguments: pwszName -- Name to hash // // Returns: Hash index of the string // //----------------------------------------------------------------------------- INT ActrlHashIdName(PWSTR pwszName) { INT Hash = 0; #if DBG PWSTR pwsz = pwszName; #endif if(pwszName != NULL) { while(*pwszName != L'\0') { Hash = (Hash * 16 + ( tolower(*pwszName++))) % ACTRL_OBJ_ID_TABLE_SIZE; } } #if DBG acDebugOut((DEB_TRACE_LOOKUP,"Hashing id name %ws to %lu\n", pwsz, Hash)); #endif return(Hash); } //+---------------------------------------------------------------------------- // // Function: ActrlHashGuid // // Synopsis: Determines the hash index for the given guid // // Arguments: pGuid -- Guid to hash // // Returns: Hash index of the Guid // //----------------------------------------------------------------------------- INT ActrlHashGuid(PGUID pGuid) { DWORD dwTotal = 0; // // Just deal with the sub authorities // for(INT i = 0; i < sizeof(GUID) / sizeof(DWORD); i++) { dwTotal += ((PULONG)pGuid)[i]; } #if DBG CHAR szGuid[38]; memset( szGuid, 0, sizeof(szGuid)); sprintf(szGuid, "%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x", pGuid->Data1,pGuid->Data2,pGuid->Data3,pGuid->Data4[0], pGuid->Data4[1],pGuid->Data4[2],pGuid->Data4[3], pGuid->Data4[4],pGuid->Data4[5],pGuid->Data4[6], pGuid->Data4[7]); acDebugOut((DEB_TRACE_LOOKUP, "Hashing id %s (Total %lu) to %lu\n", szGuid, dwTotal, dwTotal % ACTRL_OBJ_ID_TABLE_SIZE)); #endif return(dwTotal % ACTRL_OBJ_ID_TABLE_SIZE); } //+---------------------------------------------------------------------------- // // Function: AccctrlInitializeIdNameCache // // Synopsis: Initialize the ID name/Guid lookup cache // // Arguments: VOID // // Returns: ERROR_SUCCESS -- Success // //----------------------------------------------------------------------------- DWORD AccctrlInitializeIdNameCache(VOID) { DWORD dwErr; if (TRUE == bIdCacheLockInitialized) { // Just a precautionary measure to make sure that we do not initialize // multiple times. // ASSERT(FALSE); return ERROR_SUCCESS; } memset(grgIdNameCache, 0, sizeof(PACTRL_OBJ_ID_CACHE) * ACTRL_OBJ_ID_TABLE_SIZE); memset(grgIdGuidCache, 0, sizeof(PACTRL_OBJ_ID_CACHE) * ACTRL_OBJ_ID_TABLE_SIZE); gpMemCleanupList = NULL; memset(&LastSchemaRead, 0, sizeof(ACTRL_ID_SCHEMA_INFO)); __try { RtlInitializeResource(&gIdCacheLock); dwErr = ERROR_SUCCESS; bIdCacheLockInitialized = TRUE; } __except (EXCEPTION_EXECUTE_HANDLER) { dwErr = RtlNtStatusToDosError(GetExceptionCode()); } return dwErr; } //+---------------------------------------------------------------------------- // // Function: AccctrlFreeIdNameCache // // Synopsis: Frees any memory allocated for the id name/guid cache // // Arguments: VOID // // Returns: VOID // //----------------------------------------------------------------------------- VOID AccctrlFreeIdNameCache(VOID) { INT i; PACTRL_OBJ_ID_CACHE pNode, pNext; if (FALSE == bIdCacheLockInitialized) { return; } for(i = 0; i < ACTRL_OBJ_ID_TABLE_SIZE; i++) { // // Nodes are only inserted into the name cache, so that is the only // place we delete them from // pNode = grgIdNameCache[i]; while(pNode != NULL) { pNext = pNode->pNextName; AccFree(pNode->pwszName); AccFree(pNode); pNode = pNext; } } PACTRL_ID_MEM pMem = gpMemCleanupList; while(pMem != NULL) { if(pMem->fRpc == TRUE) { PWSTR pwsz = (PWSTR)pMem->pv; RpcStringFree(&pwsz); } else { AccFree(pMem->pv); } pMem = pMem->pNext; } AccFree(LastSchemaRead.pwszPath); RtlDeleteResource(&gIdCacheLock); bIdCacheLockInitialized = FALSE; } //+---------------------------------------------------------------------------- // // Function: AccctrlpLookupIdNameInCache // // Synopsis: Determines if the given name exists in the cache or not // // Arguments: [pwszName] -- Name to be looked up // // Returns: Matching node if found, NULL if not // //----------------------------------------------------------------------------- PACTRL_OBJ_ID_CACHE AccctrlpLookupNameInCache(PWSTR pwszName) { PACTRL_OBJ_ID_CACHE pNode = NULL; pNode = grgIdNameCache[ActrlHashIdName(pwszName)]; while(pNode != NULL) { if(_wcsicmp(pwszName, pNode->pwszName) == 0) { break; } pNode = pNode->pNextName; } #if DBG if(pNode != NULL ) { CHAR szGuid[38]; PGUID pGuid = &pNode->Guid; sprintf(szGuid, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", pGuid->Data1,pGuid->Data2,pGuid->Data3,pGuid->Data4[0], pGuid->Data4[1],pGuid->Data4[2],pGuid->Data4[3], pGuid->Data4[4],pGuid->Data4[5],pGuid->Data4[6], pGuid->Data4[7]); acDebugOut((DEB_TRACE_LOOKUP, "LookupName on %ws found %s\n", pwszName, szGuid)); } #endif return(pNode); } //+---------------------------------------------------------------------------- // // Function: AccctrlpLookupGuidInCache // // Synopsis: Determines if the given guid exists in the cache or not // // Arguments: [pGuid] -- Guid to be looked up // // Returns: Matching node if found, NULL if not // //----------------------------------------------------------------------------- PACTRL_OBJ_ID_CACHE AccctrlpLookupGuidInCache(PGUID pGuid) { PACTRL_OBJ_ID_CACHE pNode = grgIdGuidCache[ActrlHashGuid(pGuid)]; while(pNode != NULL) { if(memcmp(pGuid, &(pNode->Guid), sizeof(GUID)) == 0) { break; } pNode = pNode->pNextGuid; } #if DBG if(pNode != NULL ) { CHAR szGuid[37]; sprintf(szGuid, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", pGuid->Data1,pGuid->Data2,pGuid->Data3,pGuid->Data4[0], pGuid->Data4[1],pGuid->Data4[2],pGuid->Data4[3], pGuid->Data4[4],pGuid->Data4[5],pGuid->Data4[6], pGuid->Data4[7]); acDebugOut((DEB_TRACE_LOOKUP, "LookupGuid on %s found %ws\n", szGuid, pNode->pwszName)); } #endif return(pNode); } //+---------------------------------------------------------------------------- // // Function: AccctrlpNewNameGuidNode // // Synopsis: Allocates a new node and inserts them into the caches // // Arguments: [pwszName] -- Name to insert // [pGuid] -- Guid to insert // [pNewNode] -- Newly added node // // Returns: ERROR_SUCCESS -- Success // ERROR_NOT_ENOUGH_MEMORY A memory allocation failed // ERROR_INVALID_DATA A node was only inserted in one list // //----------------------------------------------------------------------------- DWORD AccctrlpNewNameGuidNode(PWSTR pwszName, PGUID pGuid, PACTRL_OBJ_ID_CACHE *ppNewNode) { DWORD dwErr = ERROR_SUCCESS; BOOL fNameRet = FALSE, fGuidRet = FALSE; PACTRL_OBJ_ID_CACHE pNewNode = (PACTRL_OBJ_ID_CACHE)AccAlloc( sizeof(ACTRL_OBJ_ID_CACHE)); if(pNewNode == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; } else { pNewNode->pwszName = pwszName; memcpy(&pNewNode->Guid, pGuid, sizeof(GUID)); pNewNode->pNextName= NULL; pNewNode->pNextGuid= NULL; fNameRet = AccctrlpInsertIdNameNode( &(grgIdNameCache[ActrlHashIdName(pwszName)]), pNewNode); if ( fNameRet == TRUE ) { fGuidRet = AccctrlpInsertGuidNode( &(grgIdGuidCache[ActrlHashGuid(pGuid)]), pNewNode); } if(fNameRet == TRUE && fGuidRet == TRUE) { *ppNewNode = pNewNode; } else { dwErr = ERROR_INVALID_DATA; if( fNameRet == TRUE ) { AccctrlpRemoveIdNameNode( &(grgIdNameCache[ActrlHashIdName(pwszName)]), pNewNode); } AccFree(pNewNode); *ppNewNode = NULL; } } return(dwErr); } //+---------------------------------------------------------------------------- // // Function: AccctrlpInsertIdNameNode // // Synopsis: Inserts the specified new node into the caches // // Arguments: [ppRootNode] -- Root node in the name cache // [pNewNode] -- Node to insert // // Returns: VOID // //----------------------------------------------------------------------------- BOOL AccctrlpInsertIdNameNode(PACTRL_OBJ_ID_CACHE *ppRootNode, PACTRL_OBJ_ID_CACHE pNewNode) { PACTRL_OBJ_ID_CACHE pNext = NULL, pTrail = NULL; BOOL fReturn = TRUE; if(*ppRootNode == NULL) { *ppRootNode = pNewNode; } else { // acDebugOut((DEB_TRACE_LOOKUP, "Collision inserting %ws with:\n", // pNewNode->pwszName)); pNext = *ppRootNode; // acDebugOut((DEB_TRACE_LOOKUP, "\t%ws\n", pNext->pwszName)); while(pNext != NULL) { if(_wcsicmp(pNewNode->pwszName, pNext->pwszName) == 0) { // // If a node is already found, exit // fReturn = FALSE; acDebugOut((DEB_TRACE_LOOKUP, "Name %ws already exists. Bailing\n", pNewNode->pwszName)); break; } pTrail = pNext; pNext = pNext->pNextName; // acDebugOut((DEB_TRACE_LOOKUP, "\t%ws\n", pNext->pwszName)); } if(fReturn == TRUE) { if ( pTrail == NULL ) { (*ppRootNode)->pNextName = pNewNode; } else { pTrail->pNextName = pNewNode; } } } return(fReturn); } //+---------------------------------------------------------------------------- // // Function: AccctrlpInsertGuidNode // // Synopsis: Inserts the specified new node into the caches // // Arguments: [ppRootNode] -- Root node in the name cache // [pNewNode] -- Node to insert // // Returns: VOID // //----------------------------------------------------------------------------- BOOL AccctrlpInsertGuidNode(PACTRL_OBJ_ID_CACHE *ppRootNode, PACTRL_OBJ_ID_CACHE pNewNode) { PACTRL_OBJ_ID_CACHE pNext = NULL, pTrail = NULL; BOOL fReturn = TRUE; if(*ppRootNode == NULL) { *ppRootNode = pNewNode; } else { // acDebugOut((DEB_TRACE_LOOKUP, "Collision inserting %ws with:\n", // pNewNode->pwszName)); pNext = *ppRootNode; // acDebugOut((DEB_TRACE_LOOKUP, "\t%ws\n", pNext->pwszName)); while(pNext != NULL) { if(memcmp(&(pNewNode->Guid), &(pNext->Guid), sizeof(GUID)) == 0) { fReturn = FALSE; acDebugOut((DEB_TRACE_LOOKUP, "Guid for %ws already exists. Bailing\n", pNewNode->pwszName)); break; } pTrail = pNext; pNext = pNext->pNextGuid; // acDebugOut((DEB_TRACE_LOOKUP, "\t%ws\n", pNext->pwszName)); } if(fReturn == TRUE) { if ( pTrail == NULL ) { (*ppRootNode)->pNextGuid = pNewNode; } else { pTrail->pNextGuid = pNewNode; } } } return(fReturn); } //+---------------------------------------------------------------------------- // // Function: AccctrlLookupIdName // // Synopsis: Looks up the name for the specified GUID. // Algorithm: // Search cache for ID // If not found, reload table from schema on DS referenced // by the DS path // Search the cache for the ID // If not found, return the string version of the ID // // Arguments: [pGuid] -- Guid to lookup // [fAllocateReturn]- If true, the name returned is allocated // into a new buffer. Otherwise, a // reference is returned. // [ppwszName] -- Where the name is returned. // // Returns: VOID // //----------------------------------------------------------------------------- DWORD AccctrlLookupIdName(IN PLDAP pLDAP, IN PWSTR pwszDsPath, IN PGUID pGuid, IN BOOL fAllocateReturn, IN BOOL fHandleObjectGuids, OUT PWSTR *ppwszName) { DWORD dwErr = ERROR_SUCCESS; PWSTR pwszStringId = NULL; RtlAcquireResourceShared(&gIdCacheLock, TRUE); #if DBG CHAR szGuid[38]; sprintf(szGuid, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", pGuid->Data1,pGuid->Data2,pGuid->Data3, pGuid->Data4[0], pGuid->Data4[1],pGuid->Data4[2],pGuid->Data4[3], pGuid->Data4[4],pGuid->Data4[5],pGuid->Data4[6], pGuid->Data4[7]); #endif // // First, see if the sid alreadt exists in our cache // PACTRL_OBJ_ID_CACHE pNode = AccctrlpLookupGuidInCache(pGuid); if(pNode == NULL) { acDebugOut((DEB_TRACE_LOOKUP, "Guid %s not found in cache\n", szGuid)); // // Grab a write lock // RtlConvertSharedToExclusive(&gIdCacheLock); // // We'll have to look it up... // dwErr = AccctrlpLoadCacheFromSchema(pLDAP, pwszDsPath); if(dwErr == ERROR_SUCCESS) { pNode = AccctrlpLookupGuidInCache(pGuid); // // If we've been asked to handle individual object guids, // see if this GUID is one. // if ( fHandleObjectGuids ) { PWSTR pwszUuid; DWORD dwUuidLen; PWSTR pwszDSObj; PDS_NAME_RESULTW pNameRes; // // Convert the GUID to a string. // dwErr = UuidToString(pGuid, &pwszUuid); if ( dwErr == ERROR_SUCCESS ) { // // Convert the string-ized GUID to an object name. // dwUuidLen = wcslen( pwszUuid ); pwszDSObj = (PWSTR) AccAlloc( (dwUuidLen+3)*sizeof(WCHAR) ); if ( pwszDSObj == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; } else { PWSTR pwszServer = NULL, pwszObject = NULL; pwszDSObj[0] = L'{'; memcpy( &pwszDSObj[1], pwszUuid, dwUuidLen*sizeof(WCHAR) ); pwszDSObj[dwUuidLen+1] = L'}'; pwszDSObj[dwUuidLen+2] = L'\0'; // // Crack the name into canonical form // dwErr = DspSplitPath( pwszDSObj, &pwszServer, &pwszObject ); if(dwErr == ERROR_SUCCESS) { dwErr = DspBindAndCrackEx( pwszServer, pwszObject, 0, DS_CANONICAL_NAME, &pNameRes ); if ( dwErr == ERROR_SUCCESS ) { if(pNameRes->cItems == 0 || pNameRes->rItems[0].status != 0) { dwErr = ERROR_SUCCESS; } else { // // Cache our newly found name. // dwErr = AccctrlpNewNameGuidNode( pNameRes->rItems[0].pName, pGuid, &pNode); } // Clean up DsFreeNameResultW(pNameRes); } else { // Failure to find name isn't fatal dwErr = ERROR_SUCCESS; } AccFree(pwszServer); } // Clean up AccFree( pwszDSObj ); } // Clean up RpcStringFree(&pwszUuid); } } // // If it wasn't found, return the string version of the ID // if( dwErr == ERROR_SUCCESS && pNode == NULL) { dwErr = UuidToString(pGuid, &pwszStringId); } } } else { acDebugOut((DEB_TRACE_LOOKUP, "Guid %s found in cache\n", szGuid)); } // // Finally, return the information // if(dwErr == ERROR_SUCCESS) { PWSTR pwszName; if(pNode != NULL) { pwszName = pNode->pwszName; } else { pwszName = pwszStringId; } if(fAllocateReturn == TRUE) { ACC_ALLOC_AND_COPY_STRINGW(pwszName, *ppwszName, dwErr); } else { *ppwszName = pwszName; if(pwszStringId != NULL) { PACTRL_ID_MEM pMem = (PACTRL_ID_MEM)AccAlloc(sizeof(ACTRL_ID_MEM)); if(pMem == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; RpcStringFree(&pwszStringId); } else { pMem->pv = pwszStringId; pMem->fRpc = TRUE; pMem->pNext = gpMemCleanupList; gpMemCleanupList = pMem; } } } } RtlReleaseResource(&gIdCacheLock); return(dwErr); } //+---------------------------------------------------------------------------- // // Function: AccctrlLookupGuid // // Synopsis: Looks up the GUID for the specified name // // Arguments: [pwszName] -- Name to lookup // [fAllocateReturn]- If true, the name returned is allocated // into a new buffer. Otherwise, a // reference is returned. // [ppGuid] -- Where the guid is returned. // // Returns: VOID // //----------------------------------------------------------------------------- DWORD AccctrlLookupGuid(IN PLDAP pLDAP, IN PWSTR pwszDsPath, IN PWSTR pwszName, IN BOOL fAllocateReturn, OUT PGUID *ppGuid) { DWORD dwErr = ERROR_SUCCESS; GUID guid, *pguid = NULL; BOOL fConverted = FALSE; RtlAcquireResourceShared(&gIdCacheLock, TRUE); // // First, see if the sid already exists in our cache // PACTRL_OBJ_ID_CACHE pNode = AccctrlpLookupNameInCache(pwszName); if(pNode == NULL) { // // Grab a write lock // RtlConvertSharedToExclusive(&gIdCacheLock); acDebugOut((DEB_TRACE_LOOKUP,"Name %ws not found in cache\n", pwszName)); // // We'll have to look it up... // dwErr = AccctrlpLoadCacheFromSchema(pLDAP, pwszDsPath); if(dwErr == ERROR_SUCCESS) { pNode = AccctrlpLookupNameInCache(pwszName); // // If it wasn't found, return the ID from the string // if(pNode == NULL) { dwErr = UuidFromString(pwszName, &guid); fConverted = TRUE; pguid = &guid; } else { pguid = &pNode->Guid; } } } else { acDebugOut((DEB_TRACE_LOOKUP,"Name %ws found in cache\n", pwszName)); pguid = &pNode->Guid; } // // Finally, return the information // if(dwErr == ERROR_SUCCESS) { if(fAllocateReturn == TRUE) { ACC_ALLOC_AND_COPY_GUID(pguid, *ppGuid, dwErr); } else { if(fConverted == TRUE) { ACC_ALLOC_AND_COPY_GUID(pguid, *ppGuid, dwErr); if(dwErr == ERROR_SUCCESS) { PACTRL_ID_MEM pMem = (PACTRL_ID_MEM)AccAlloc( sizeof(ACTRL_ID_MEM)); if(pMem == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; AccFree(*ppGuid); } else { pMem->pv = *ppGuid; pMem->pNext = gpMemCleanupList; gpMemCleanupList = pMem; } } } else { *ppGuid = pguid; } } } RtlReleaseResource(&gIdCacheLock); return(dwErr); } #define WCHAR_TO_HEX_BYTE(wc) \ (BYTE)((wc) >= L'0' && (wc) <= L'9' ? (wc) - L'0' : towlower( (wc) ) - L'a' + 10) #define WCHAR_TO_HI_HEX_BYTE(wc) (WCHAR_TO_HEX_BYTE(wc) << 4 ) //+---------------------------------------------------------------------------- // // Function: AccctrlpDsStrGuidToGuid // // Synopsis: Converts a read string guid into an actual guid // // Arguments: [pwszStrGuid] -- String version of the id // [pGuid] -- Where the build ID is returned // // Returns: ERROR_SUCCESS -- Success // //----------------------------------------------------------------------------- DWORD AccctrlpDsStrGuidToGuid(IN PWSTR pwszStrGuid, OUT PGUID pGuid) { DWORD dwErr = ERROR_SUCCESS; if(pwszStrGuid == NULL || wcsstr(pwszStrGuid, L"'") - pwszStrGuid != sizeof(GUID) * sizeof(WCHAR)) { dwErr = ERROR_INVALID_PARAMETER; } else { #if 1 // // The string guid we're given is not in a standard UuidToString form, // so we'll have to convert it // PBYTE pCurr = (PBYTE)pGuid; for(ULONG i = 0; i < sizeof(GUID); i++) { *pCurr = WCHAR_TO_HI_HEX_BYTE(*pwszStrGuid) | WCHAR_TO_HEX_BYTE(*(pwszStrGuid + 1)); pCurr++; pwszStrGuid += 2; } #else // // Whack it into the right form... // WCHAR wszStrFormat[sizeof(GUID) * sizeof(WCHAR) + 7]; ULONG Blocks[] = {8, 4, 4, 4, 12}; PWSTR pwszStrFor = wszStrFormat; for(ULONG i = 0 ; i < sizeof(Blocks) / sizeof(ULONG) ; i++ ) { for(ULONG j = 0; j < Blocks[i]; j++) { *pwszStrFor++ = *pwszStrGuid++; } *pwszStrFor++ = L'-'; } pwszStrFor--; *pwszStrFor = UNICODE_NULL; dwErr = UuidFromString(wszStrFormat, pGuid); #endif } return(dwErr); } //+---------------------------------------------------------------------------- // // Function: AccctrlpLoadCacheFromSchema // // Synopsis: Reads the schema cache and adds the entries into the // cache // // Arguments: [pLDAP] -- LDAP connection to the server // [pwszPath] -- DS path to the object // // Returns: ERROR_SUCCESS -- Success // //----------------------------------------------------------------------------- DWORD AccctrlpLoadCacheFromSchema(PLDAP pLDAP, PWSTR pwszDsPath) { DWORD dwErr = ERROR_SUCCESS; PLDAP pLocalLDAP = pLDAP; ULONG cValues[2]; PWSTR *ppwszValues[2]; PWSTR rgwszGuidStrs[] = {ACTRL_OBJ_CLASS, ACTRL_OBJ_GUID}; ULONG rgGuidStrLen[] = {ACTRL_OBJ_CLASS_LEN, ACTRL_OBJ_GUID_LEN}; acDebugOut((DEB_TRACE_LOOKUP, "Reloading cache from schema\n")); // // If we have no parameters, just return... // if(pLDAP == NULL && pwszDsPath == NULL) { return(ERROR_SUCCESS); } // // See if we need to read... If our data is over 5 minutes old or if our path referenced is // not the same as the last one... // #define FIVE_MINUTES 300000 if((LastSchemaRead.LastReadTime != 0 && (GetTickCount() - LastSchemaRead.LastReadTime < FIVE_MINUTES)) && DoPropertiesMatch(pwszDsPath, LastSchemaRead.pwszPath) && ((pLDAP == NULL && LastSchemaRead.fLDAP == FALSE) || (pLDAP != NULL && memcmp(pLDAP, &(LastSchemaRead.LDAP), sizeof(LDAP))))) { acDebugOut((DEB_TRACE_LOOKUP,"Cache up to date...\n")); return(ERROR_SUCCESS); } else { // // Need to reinitialize it... // if(pLDAP == NULL) { LastSchemaRead.fLDAP = FALSE; } else { LastSchemaRead.fLDAP = TRUE; memcpy(&(LastSchemaRead.LDAP), pLDAP, sizeof(LDAP)); } AccFree(LastSchemaRead.pwszPath); if(pwszDsPath != NULL) { ACC_ALLOC_AND_COPY_STRINGW(pwszDsPath, LastSchemaRead.pwszPath, dwErr); } LastSchemaRead.LastReadTime = GetTickCount(); } if(dwErr == ERROR_SUCCESS && pLocalLDAP == NULL) { PWSTR pwszServer = NULL, pwszObject = NULL; dwErr = DspSplitPath( pwszDsPath, &pwszServer, &pwszObject ); if(dwErr == ERROR_SUCCESS) { dwErr = BindToDSObject(pwszServer, pwszObject, &pLocalLDAP); LocalFree(pwszServer); } } // // Now, get the info. First, extended rights, then the schema info // if(dwErr == ERROR_SUCCESS) { dwErr = AccDsReadExtendedRights(pLocalLDAP, &(cValues[0]), &(ppwszValues[0]), &(ppwszValues[1])); if(dwErr == ERROR_SUCCESS ) { for(ULONG j = 0; j < cValues[0] && dwErr == ERROR_SUCCESS; j++) { GUID guid; dwErr = UuidFromString(ppwszValues[1][j], &guid); if(dwErr == ERROR_SUCCESS) { PACTRL_OBJ_ID_CACHE pNewNode; PWSTR pwsz; ACC_ALLOC_AND_COPY_STRINGW(ppwszValues[0][j], pwsz, dwErr); if(dwErr == ERROR_SUCCESS ) { dwErr = AccctrlpNewNameGuidNode(pwsz, &guid, &pNewNode); if(dwErr != ERROR_SUCCESS) { AccFree(pwsz); if ( dwErr == ERROR_INVALID_DATA ) { dwErr = ERROR_SUCCESS; } } } } } AccDsFreeExtendedRights(cValues[0], ppwszValues[0], ppwszValues[1]); } if(dwErr == ERROR_SUCCESS) { dwErr = AccDsReadSchemaInfo(pLocalLDAP, &(cValues[0]), &(ppwszValues[0]), &(cValues[1]), &(ppwszValues[1])); if(dwErr == ERROR_SUCCESS ) { for(ULONG i = 0; i < 2 && dwErr == ERROR_SUCCESS; i++) { for(ULONG j = 0; j < cValues[i] && dwErr == ERROR_SUCCESS; j++) { PWSTR pwszVal = ppwszValues[i][j]; GUID guid; PWSTR pwszName, pwszGuid, pwszTick; pwszName = wcswcs(pwszVal, ACTRL_OBJ_NAME) + ACTRL_OBJ_NAME_LEN; pwszGuid = wcswcs(pwszName, rgwszGuidStrs[i]) + rgGuidStrLen[i]; pwszTick = wcswcs(pwszName, L"'"); if(pwszTick != NULL) { *pwszTick = UNICODE_NULL; } dwErr = AccctrlpDsStrGuidToGuid(pwszGuid, &guid); if(dwErr == ERROR_SUCCESS) { PACTRL_OBJ_ID_CACHE pNewNode; PWSTR pwsz; ACC_ALLOC_AND_COPY_STRINGW(pwszName, pwsz, dwErr); if(dwErr == ERROR_SUCCESS ) { dwErr = AccctrlpNewNameGuidNode(pwsz, &guid, &pNewNode); if(dwErr != ERROR_SUCCESS) { AccFree(pwsz); if ( dwErr == ERROR_INVALID_DATA ) { dwErr = ERROR_SUCCESS; } } } } pwszVal = pwszGuid; } } ldap_value_free(ppwszValues[0]); ldap_value_free(ppwszValues[1]); } } } // // See if we need to release our ldap connection // if(pLocalLDAP != pLDAP && pLocalLDAP != NULL) { UnBindFromDSObject(&pLocalLDAP); } return(dwErr); } //+---------------------------------------------------------------------------- // // Function: AccctrlpRemoveIdNameNode // // Synopsis: Removes the specified new node into the caches // // Arguments: [ppRootNode] -- Root node in the name cache // [pNewNode] -- Node to remove // // Returns: VOID // //----------------------------------------------------------------------------- VOID AccctrlpRemoveIdNameNode(PACTRL_OBJ_ID_CACHE *ppRootNode, PACTRL_OBJ_ID_CACHE pNewNode) { PACTRL_OBJ_ID_CACHE pNext = NULL, pPrev; ASSERT( *ppRootNode != NULL ); if(_wcsicmp((*ppRootNode)->pwszName, pNewNode->pwszName) == 0) { *ppRootNode = NULL; } else { pNext = (*ppRootNode)->pNextName; pPrev = *ppRootNode; while(pNext != NULL) { if(_wcsicmp(pNewNode->pwszName, pNext->pwszName) == 0) { // // Remove the node // pPrev->pNextName = pNext->pNextName; acDebugOut((DEB_TRACE_LOOKUP, "Removed node for %ws\n", pNext->pwszName)); break; } pPrev = pNext; pNext = pNext->pNextName; } } return; }