//************************************************************* // // Group Policy Support - Queries about the Policies // // Microsoft Confidential // Copyright (c) Microsoft Corporation 1997-1998 // All rights reserved // //************************************************************* #include "gphdr.h" #include //************************************************************* // // AddGPO() // // Purpose: Adds a GPO to the list // // Parameters: lpGPOList - list of GPOs // dwFlags - Flags // bFound - Was Gpo found ? // bAccessGranted - Was access granted ? // bDisabled - Is this Gpo disabled ? // dwOptions - Options // dwVersion - Version number // lpDSPath - DS path // lpFileSysPath - File system path // lpDisplayName - Friendly display name // lpGPOName - GPO name // lpExtensions - Extensions relevant to this GPO // lpDSObject - LSDOU // pSD - Ptr to security descriptor // cbSDLen - Length of security descriptor in bytes // GPOLink - GPO link type // lpLink - SDOU this GPO is linked to // lParam - lParam // bFront - Head or end of list // bBlock - Block from above flag // bVerbose - Verbose output flag // // // Return: TRUE if successful // FALSE if an error occurs // //************************************************************* BOOL AddGPO (PGROUP_POLICY_OBJECT * lpGPOList, DWORD dwFlags, BOOL bFound, BOOL bAccessGranted, BOOL bDisabled, DWORD dwOptions, DWORD dwVersion, LPTSTR lpDSPath, LPTSTR lpFileSysPath, LPTSTR lpDisplayName, LPTSTR lpGPOName, LPTSTR lpExtensions, PSECURITY_DESCRIPTOR pSD, DWORD cbSDLen, GPO_LINK GPOLink, LPTSTR lpLink, LPARAM lParam, BOOL bFront, BOOL bBlock, BOOL bVerbose, BOOL bProcessGPO) { PGROUP_POLICY_OBJECT lpNew, lpTemp; DWORD dwSize; XLastError xe; HRESULT hr = S_OK; // // Check if this item should be excluded from the list // if (bBlock) { if (!(dwOptions & GPO_FLAG_FORCE)) { DebugMsg((DM_VERBOSE, TEXT("AddGPO: GPO %s will not be added to the list since the Block flag is set and this GPO is not in enforce mode."), lpDisplayName)); if (bVerbose) { CEvents ev(FALSE, EVENT_SKIP_GPO); ev.AddArg(lpDisplayName); ev.Report(); } if (dwFlags & GP_PLANMODE) { DebugMsg((DM_VERBOSE, TEXT("AddGPO: GPO %s will will still be queried for since this is planning mode."), lpDisplayName)); bProcessGPO = FALSE; } else return TRUE; } } // // Calculate the size of the new GPO item // dwSize = sizeof (GROUP_POLICY_OBJECT); if (lpDSPath) { dwSize += ((lstrlen(lpDSPath) + 1) * sizeof(TCHAR)); } if (lpFileSysPath) { dwSize += ((lstrlen(lpFileSysPath) + 1) * sizeof(TCHAR)); } if (lpDisplayName) { dwSize += ((lstrlen(lpDisplayName) + 1) * sizeof(TCHAR)); } if (lpExtensions) { dwSize += ((lstrlen(lpExtensions) + 1) * sizeof(TCHAR)); } if (lpLink) { dwSize += ((lstrlen(lpLink) + 1) * sizeof(TCHAR)); } dwSize += sizeof(GPOPROCDATA); // // Allocate space for it // lpNew = (PGROUP_POLICY_OBJECT) LocalAlloc (LPTR, dwSize); if (!lpNew) { DebugMsg((DM_WARNING, TEXT("AddGPO: Failed to allocate memory with %d"), GetLastError())); return FALSE; } // // Fill in item // LPGPOPROCDATA lpGpoProcData; lpNew->lParam2 = (LPARAM)(((LPBYTE)lpNew) + sizeof(GROUP_POLICY_OBJECT)); lpGpoProcData = (LPGPOPROCDATA)lpNew->lParam2; lpGpoProcData->bProcessGPO = bProcessGPO; lpNew->dwOptions = dwOptions; lpNew->dwVersion = dwVersion; if (lpDSPath) { lpNew->lpDSPath = (LPTSTR)(((LPBYTE)lpNew) + sizeof(GROUP_POLICY_OBJECT) + sizeof(GPOPROCDATA)); hr = StringCchCopy (lpNew->lpDSPath, lstrlen(lpDSPath) + 1, lpDSPath); ASSERT(SUCCEEDED(hr)); } if (lpFileSysPath) { if (lpDSPath) { lpNew->lpFileSysPath = lpNew->lpDSPath + lstrlen (lpNew->lpDSPath) + 1; } else { lpNew->lpFileSysPath = (LPTSTR)(((LPBYTE)lpNew) + sizeof(GROUP_POLICY_OBJECT) + sizeof(GPOPROCDATA)); } hr = StringCchCopy (lpNew->lpFileSysPath, lstrlen(lpFileSysPath) + 1, lpFileSysPath); ASSERT(SUCCEEDED(hr)); } if (lpDisplayName) { if (lpFileSysPath) { lpNew->lpDisplayName = lpNew->lpFileSysPath + lstrlen (lpNew->lpFileSysPath) + 1; } else { if (lpDSPath) { lpNew->lpDisplayName = lpNew->lpDSPath + lstrlen (lpNew->lpDSPath) + 1; } else { lpNew->lpDisplayName = (LPTSTR)(((LPBYTE)lpNew) + sizeof(GROUP_POLICY_OBJECT) + sizeof(GPOPROCDATA)); } } hr = StringCchCopy (lpNew->lpDisplayName, lstrlen(lpDisplayName) + 1, lpDisplayName); ASSERT(SUCCEEDED(hr)); } if (lpGPOName) { DmAssert( lstrlen(lpGPOName) < 50 ); hr = StringCchCopy (lpNew->szGPOName, 50, lpGPOName); ASSERT(SUCCEEDED(hr)); } if (lpExtensions) { if (lpDisplayName) { lpNew->lpExtensions = lpNew->lpDisplayName + lstrlen(lpNew->lpDisplayName) + 1; } else { if (lpFileSysPath) { lpNew->lpExtensions = lpNew->lpFileSysPath + lstrlen(lpNew->lpFileSysPath) + 1; } else { if (lpDSPath) { lpNew->lpExtensions = lpNew->lpDSPath + lstrlen(lpNew->lpDSPath) + 1; } else { lpNew->lpExtensions = (LPTSTR)(((LPBYTE)lpNew) + sizeof(GROUP_POLICY_OBJECT) + sizeof(GPOPROCDATA)); } } } hr = StringCchCopy (lpNew->lpExtensions, lstrlen(lpExtensions) + 1, lpExtensions); ASSERT(SUCCEEDED(hr)); } if (lpLink) { if (lpExtensions) { lpNew->lpLink = lpNew->lpExtensions + lstrlen(lpNew->lpExtensions) + 1; } else { if (lpDisplayName) { lpNew->lpLink = lpNew->lpDisplayName + lstrlen(lpNew->lpDisplayName) + 1; } else { if (lpFileSysPath) { lpNew->lpLink = lpNew->lpFileSysPath + lstrlen(lpNew->lpFileSysPath) + 1; } else { if (lpDSPath) { lpNew->lpLink = lpNew->lpDSPath + lstrlen(lpNew->lpDSPath) + 1; } else { lpNew->lpLink = (LPTSTR)(((LPBYTE)lpNew) + sizeof(GROUP_POLICY_OBJECT) + sizeof(GPOPROCDATA)); } } } } hr = StringCchCopy (lpNew->lpLink, lstrlen(lpLink) + 1, lpLink); ASSERT(SUCCEEDED(hr)); } lpNew->GPOLink = GPOLink; lpNew->lParam = lParam; // // Add item to link list // if (*lpGPOList) { if (bFront) { (*lpGPOList)->pPrev = lpNew; lpNew->pNext = *lpGPOList; *lpGPOList = lpNew; } else { lpTemp = *lpGPOList; while (lpTemp->pNext != NULL) { lpTemp = lpTemp->pNext; } lpTemp->pNext = lpNew; lpNew->pPrev = lpTemp; } } else { // // First item in the list // *lpGPOList = lpNew; } return TRUE; } //************************************************************* // // AddGPOToRsopList // // Purpose: Adds GPO to list of GPOs being logged by Rsop // // Parameters: ppGpContainerList - List of Gp Containers // dwFlags - Flags // bFound - Was Gpo found ? // bAccessGranted - Was access granted ? // bDisabled - Is this Gpo disabled ? // dwOptions - Options // dwVersion - Version number // lpDSPath - DS path // lpFileSysPath - File system path // lpDisplayName - Friendly display name // lpGPOName - GPO name // pSD - Pointer to security descriptor // cbSDLen - Length of security descriptor in bytes // bFilterAllowed - Does GPO pass filter check // pwszFilterId - WQL filter id // szSOM - SOM // dwGPOOptions - GPO options // //************************************************************* BOOL AddGPOToRsopList( LPGPCONTAINER *ppGpContainerList, DWORD dwFlags, BOOL bFound, BOOL bAccessGranted, BOOL bDisabled, DWORD dwVersion, LPTSTR lpDSPath, LPTSTR lpFileSysPath, LPTSTR lpDisplayName, LPTSTR lpGPOName, PSECURITY_DESCRIPTOR pSD, DWORD cbSDLen, BOOL bFilterAllowed, WCHAR *pwszFilterId, LPWSTR szSOM, DWORD dwOptions) { // Fixing bug 568213 XLastError xe; GPCONTAINER *pGpContainer = AllocGpContainer( dwFlags, bFound, bAccessGranted, bDisabled, dwVersion, lpDSPath, lpFileSysPath, lpDisplayName, lpGPOName, pSD, cbSDLen, bFilterAllowed, pwszFilterId, szSOM, dwOptions ); if ( pGpContainer == NULL ) { DebugMsg((DM_VERBOSE, TEXT("AddGPO: Failed to allocate memory for Gp Container."))); return FALSE; } // // Prepend to GpContainer list // pGpContainer->pNext = *ppGpContainerList; *ppGpContainerList = pGpContainer; return TRUE; } //************************************************************* // // AddLocalGPO() // // Purpose: Adds a local Gpo to the list of SOMs // // Parameters: ppSOMList - List of SOMs // //************************************************************* BOOL AddLocalGPO( LPSCOPEOFMGMT *ppSOMList ) { GPLINK *pGpLink = NULL; XLastError xe; SCOPEOFMGMT *pSOM = AllocSOM( L"Local" ); if ( pSOM == NULL ) { DebugMsg((DM_WARNING, TEXT("AddLocalGPO: Unable to allocate memory for SOM object"))); return FALSE; } pSOM->dwType = GPLinkMachine; // Local GPO cannot be blocked from above pGpLink = AllocGpLink( L"LocalGPO", 0 ); if ( pGpLink == NULL ) { xe = GetLastError(); DebugMsg((DM_WARNING, TEXT("AddLocalGPO: Unable to allocate memory for GpLink object"))); FreeSOM( pSOM ); return FALSE; } pSOM->pGpLinkList = pGpLink; pSOM->pNext = *ppSOMList; *ppSOMList = pSOM; return TRUE; } //************************************************************* // // ProcessGPO() // // Purpose: Processes a specific GPO // // Parameters: lpGPOPath - Path to the GPO // lpDSPath - DS object // dwFlags - GetGPOList flags // HANDLE - user or machine aceess token // lpGPOList - List of GPOs // ppGpContainerList - List of Gp containers // dwGPOOptions - Link options // bDeferred - Should ldap query be deferred ? // bVerbose - Verbose output // GPOLink - GPO link type // lpDSObject - SDOU this gpo is linked to // pld - LDAP info // pLDAP - LDAP api // pLdapMsg - LDAP message // bBlock - Block flag // bRsopToken - Rsop security token // pGpoFilter - Gpo filter // pLocator - WMI interface class // bAddGPO - In planning mode we want to get the gpodata even if // the GPO is not going to be applied // // // Return: TRUE if successful // FALSE if an error occurs // //************************************************************* BOOL ProcessGPO(LPTSTR lpGPOPath, DWORD dwFlags, HANDLE hToken, PGROUP_POLICY_OBJECT *lpGPOList, LPGPCONTAINER *ppGpContainerList, DWORD dwGPOOptions, BOOL bDeferred, BOOL bVerbose, GPO_LINK GPOLink, LPTSTR lpDSObject, PLDAP pld, PLDAP_API pLDAP, PLDAPMessage pMessage, BOOL bBlock, PRSOPTOKEN pRsopToken, CGpoFilter *pGpoFilter, CLocator *pLocator, BOOL bProcessGPO ) { ULONG ulResult, i; BOOL bResult = FALSE; BOOL bFound = FALSE; BOOL bOwnLdapMsg = FALSE; // LDAP message owned by us (if true) or caller (if false) BOOL bAccessGranted; DWORD dwFunctionalityVersion = 2; DWORD dwVersion = 0; DWORD dwGPOFlags = 0; DWORD dwGPTVersion = 0; TCHAR szGPOName[80]; TCHAR *pszGPTPath = 0; TCHAR *pszFriendlyName = 0; LPTSTR lpPath, lpEnd, lpTemp; TCHAR *pszExtensions = 0; TCHAR szLDAP[] = TEXT("LDAP://"); INT iStrLen = lstrlen(szLDAP); BYTE berValue[8]; LDAPControl SeInfoControl = { LDAP_SERVER_SD_FLAGS_OID_W, { 5, (PCHAR)berValue }, TRUE }; LDAPControl referralControl = { LDAP_SERVER_DOMAIN_SCOPE_OID_W, { 0, NULL}, TRUE }; PLDAPControl ServerControls[] = { &SeInfoControl, &referralControl, NULL }; TCHAR szSDProperty[] = TEXT("nTSecurityDescriptor"); TCHAR szCommonName[] = TEXT("cn"); TCHAR szDisplayName[] = TEXT("displayName"); TCHAR szFileSysPath[] = TEXT("gPCFileSysPath"); TCHAR szVersion[] = TEXT("versionNumber"); TCHAR szFunctionalityVersion[] = GPO_FUNCTIONALITY_VERSION; TCHAR szFlags[] = TEXT("flags"); TCHAR szWmiFilter[] = TEXT("gPCWQLFilter"); PWSTR rgAttribs[12] = {szSDProperty, szFileSysPath, szCommonName, szDisplayName, szVersion, szFunctionalityVersion, szFlags, GPO_MACHEXTENSION_NAMES, GPO_USEREXTENSION_NAMES, szObjectClass, szWmiFilter, NULL }; LPTSTR *lpValues; PSECURITY_DESCRIPTOR pSD = NULL; // Security Descriptor DWORD cbSDLen = 0; // Length of security descriptor in bytes BOOL bRsopLogging = (ppGpContainerList != NULL); BOOL bOldGpoVersion = FALSE; BOOL bDisabled = FALSE; BOOL bNoGpoData = FALSE; BOOL bFilterAllowed = FALSE; WCHAR *pwszFilterId = NULL; XLastError xe; HRESULT hr = S_OK; // // Verbose output // DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: =============================="))); // // Skip the starting LDAP provider if found // if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE, lpGPOPath, iStrLen, szLDAP, iStrLen) == CSTR_EQUAL) { lpPath = lpGPOPath + iStrLen; } else { lpPath = lpGPOPath; } if ( bDeferred ) { bResult = AddGPO (lpGPOList, dwFlags, TRUE, TRUE, FALSE, dwGPOOptions, 0, lpPath, 0, 0, 0, 0, 0, 0, GPOLink, lpDSObject, 0, FALSE, bBlock, bVerbose, bProcessGPO); if (!bResult) DebugMsg((DM_WARNING, TEXT("ProcessGPO: Failed to add GPO <%s> to the list."), lpPath)); DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: Deferring search for <%s>"), lpGPOPath)); return bResult; } DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: Searching <%s>"), lpGPOPath)); // // Check if this user or machine has access to the GPO, and if so, // should that GPO be applied to them. // if (!CheckGPOAccess (pld, pLDAP, hToken, pMessage, szSDProperty, dwFlags, &pSD, &cbSDLen, &bAccessGranted, pRsopToken)) { xe = GetLastError(); DebugMsg((DM_WARNING, TEXT("ProcessGPO: CheckGPOAccess failed for <%s>"), lpGPOPath)); CEvents ev(TRUE, EVENT_FAILED_ACCESS_CHECK); ev.AddArg(lpGPOPath); ev.AddArgWin32Error(GetLastError()); ev.Report(); goto Exit; } if (!bAccessGranted) { if (dwFlags & GPO_LIST_FLAG_MACHINE) { DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: Machine does not have access to the GPO and so will not be applied."))); } else { DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: User does not have access to the GPO and so will not be applied."))); } if (bVerbose) { CEvents ev(FALSE, EVENT_NO_ACCESS); ev.AddArg(lpGPOPath); ev.Report(); } bResult = TRUE; // GPO is not getting applied if ( !bRsopLogging ) { goto Exit; } } else { if (dwFlags & GPO_LIST_FLAG_MACHINE) { DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: Machine has access to this GPO."))); } else { DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: User has access to this GPO."))); } } // only if access is granted will we eval WQL filters if ( bAccessGranted ) { if (!FilterCheck(pld, pLDAP, pMessage, pRsopToken, szWmiFilter, pGpoFilter, pLocator, &bFilterAllowed, &pwszFilterId ) ) { xe = GetLastError(); if (xe == WBEM_E_NOT_FOUND) { DebugMsg((DM_WARNING, TEXT("ProcessGPO: CheckFilterAcess failed for <%s>. Filter not found"), lpGPOPath)); CEvents ev(TRUE, EVENT_WMIFILTER_NOTFOUND); ev.AddArg(lpGPOPath); ev.Report(); bFilterAllowed = FALSE; } else if (xe == HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED)) { DebugMsg((DM_WARNING, TEXT("ProcessGPO: CheckFilterAcess failed for <%s>. WMI service is disabled"), lpGPOPath)); CEvents ev(TRUE, EVENT_WMISERVICE_DISABLED); ev.AddArg(lpGPOPath); ev.Report(); bFilterAllowed = FALSE; } else { DebugMsg((DM_WARNING, TEXT("ProcessGPO: CheckFilterAcess failed for <%s>"), lpGPOPath)); CEvents ev(TRUE, EVENT_FAILED_FILTER_CHECK); ev.AddArg(lpGPOPath); ev.Report(); goto Exit; } } if ( (dwFlags & GP_PLANMODE) && (dwFlags & GPO_LIST_FLAG_MACHINE) && (dwFlags & FLAG_ASSUME_COMP_WQLFILTER_TRUE) ) { bFilterAllowed = TRUE; DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: Machine WQL filter is assumed to be true."))); } else if ( (dwFlags & GP_PLANMODE) && ((dwFlags & GPO_LIST_FLAG_MACHINE) == 0) && (dwFlags & FLAG_ASSUME_USER_WQLFILTER_TRUE) ) { bFilterAllowed = TRUE; DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: User WQL filter is assumed to be true."))); } if (!bFilterAllowed) { DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: The GPO does not pass the filter check and so will not be applied."))); if (bVerbose) { CEvents ev(FALSE, EVENT_NO_FILTER_ALLOWED); ev.AddArg(lpGPOPath); ev.Report(); } bResult = TRUE; // GPO is not getting applied if ( !bRsopLogging ) { goto Exit; } } else { DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: GPO passes the filter check."))); } } else { bFilterAllowed = FALSE; } // // Either user has access to this GPO, or Rsop logging is enabled so retrieve remaining GPO attributes // // // Check if this object is a GPO // lpValues = pLDAP->pfnldap_get_values(pld, pMessage, szObjectClass); if (lpValues) { bFound = FALSE; for ( i=0; lpValues[i] != NULL; i++) { if ( lstrcmp( lpValues[i], szDSClassGPO ) == 0 ) { bFound = TRUE; break; } } pLDAP->pfnldap_value_free (lpValues); if ( !bFound ) { xe = ERROR_DS_MISSING_REQUIRED_ATT; // seems like objectclass=dsgpo is required attr DebugMsg((DM_WARNING, TEXT("ProcessGPO: Object <%s> is not a GPO"), lpGPOPath )); CEvents ev(TRUE, EVENT_INCORRECT_CLASS); ev.AddArg(lpGPOPath); ev.AddArg(szDSClassGPO); ev.Report(); goto Exit; } } // // In the results, get the values that match the gPCFunctionalityVersion attribute // lpValues = pLDAP->pfnldap_get_values(pld, pMessage, szFunctionalityVersion); if (lpValues) { dwFunctionalityVersion = StringToInt (*lpValues); DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: Found functionality version of: %d"), dwFunctionalityVersion)); pLDAP->pfnldap_value_free (lpValues); } else { ulResult = pLDAP->pfnLdapGetLastError(); if (ulResult == LDAP_NO_SUCH_ATTRIBUTE) { if (dwFlags & GPO_LIST_FLAG_MACHINE) { DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: Machine does not have access to <%s>"), lpGPOPath)); } else { DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: User does not have access to <%s>"), lpGPOPath)); } if (bVerbose) { CEvents ev(FALSE, EVENT_NO_ACCESS); ev.AddArg(lpGPOPath); ev.Report(); } bResult = TRUE; } else { xe = pLDAP->pfnLdapMapErrorToWin32(ulResult); DebugMsg((DM_WARNING, TEXT("ProcessGPO: GPO %s does not have a functionality version number, error = 0x%x."), lpGPOPath, ulResult)); CEvents ev(TRUE, EVENT_CORRUPT_GPO_FUNCVERSION); ev.AddArg(lpGPOPath); ev.Report(); } goto Exit; } // // In the results, get the values that match the gPCFileSystemPath attribute // lpValues = pLDAP->pfnldap_get_values (pld, pMessage, szFileSysPath); if (lpValues) { // Fixing bug 568261 DWORD dwGPTPathLength = lstrlen(*lpValues) + MAX(lstrlen(TEXT("\\Machine")), lstrlen(TEXT("\\gpt.ini"))) + 1; //Take the MAX of MACHINE and gpt.ini pszGPTPath = (LPWSTR) LocalAlloc( LPTR, (dwGPTPathLength) * sizeof(TCHAR) ); if ( pszGPTPath == 0) { xe = GetLastError(); DebugMsg((DM_WARNING, TEXT("ProcessGPO: Unable to allocate memory"))); pLDAP->pfnldap_value_free (lpValues); goto Exit; } hr = StringCchCopy (pszGPTPath, dwGPTPathLength, *lpValues); ASSERT(SUCCEEDED(hr)); DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: Found file system path of: <%s>"), pszGPTPath)); pLDAP->pfnldap_value_free (lpValues); lpEnd = CheckSlash (pszGPTPath); // // Get the GPT version number // hr = StringCchCopy (lpEnd, dwGPTPathLength - (lpEnd - pszGPTPath), TEXT("gpt.ini")); ASSERT(SUCCEEDED(hr)); // // Skip access to sysvol if AGP or filtercheck fails // if (bAccessGranted && bFilterAllowed) { WIN32_FILE_ATTRIBUTE_DATA fad; // // Check for the existence of the gpt.ini file. // if (GetFileAttributesEx(pszGPTPath, GetFileExInfoStandard, &fad)) { dwGPTVersion = GetPrivateProfileInt(TEXT("General"), TEXT("Version"), 0, pszGPTPath); } else { xe = GetLastError(); DebugMsg((DM_WARNING, TEXT("ProcessGPO: Couldn't find the group policy template file <%s>, error = 0x%x."), pszGPTPath, GetLastError())); CEvents ev(TRUE, EVENT_GPT_NOTACCESSIBLE); ev.AddArg(lpGPOPath); ev.AddArg(pszGPTPath); ev.AddArgWin32Error(GetLastError()); ev.Report(); goto Exit; } } else { DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: Sysvol access skipped because GPO is not getting applied."))); dwGPTVersion = 0xffffffff; } if (dwFlags & GPO_LIST_FLAG_MACHINE) { hr = StringCchCopy (lpEnd, dwGPTPathLength - (lpEnd - pszGPTPath), TEXT("Machine")); } else { hr = StringCchCopy (lpEnd, dwGPTPathLength - (lpEnd - pszGPTPath), TEXT("User")); } ASSERT(SUCCEEDED(hr)); } else { ulResult = pLDAP->pfnLdapGetLastError(); if (ulResult == LDAP_NO_SUCH_ATTRIBUTE) { if (dwFlags & GPO_LIST_FLAG_MACHINE) { DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: Machine does not have access to <%s>"), lpGPOPath)); } else { DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: User does not have access to <%s>"), lpGPOPath)); } if (bVerbose) { CEvents ev(FALSE, EVENT_NO_ACCESS); ev.AddArg(lpGPOPath); ev.Report(); } bResult = TRUE; } else { xe = pLDAP->pfnLdapMapErrorToWin32(ulResult); DebugMsg((DM_WARNING, TEXT("ProcessGPO: GPO %s does not have a file system path, error = 0x%x."), lpGPOPath, ulResult)); CEvents ev(TRUE, EVENT_CORRUPT_GPO_FSPATH); ev.AddArg(lpGPOPath); ev.Report(); } goto Exit; } // // In the results, get the values that match the common name attribute // lpValues = pLDAP->pfnldap_get_values(pld, pMessage, szCommonName); if (lpValues && ValidateGuid(*lpValues)) { DmAssert( lstrlen(*lpValues) < 80 ); hr = StringCchCopy (szGPOName, ARRAYSIZE(szGPOName), *lpValues); if (FAILED(hr)) { xe = ERROR_INSUFFICIENT_BUFFER; CEvents ev(TRUE, EVENT_CORRUPT_GPO_COMMONNAME); ev.AddArg(lpGPOPath); ev.Report(); goto Exit; } DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: Found common name of: <%s>"), szGPOName)); pLDAP->pfnldap_value_free (lpValues); } else { ulResult = pLDAP->pfnLdapGetLastError(); xe = pLDAP->pfnLdapMapErrorToWin32(ulResult); DebugMsg((DM_WARNING, TEXT("ProcessGPO: GPO %s does not have a common name (a GUID)."), lpGPOPath)); CEvents ev(TRUE, EVENT_CORRUPT_GPO_COMMONNAME); ev.AddArg(lpGPOPath); ev.Report(); goto Exit; } // // In the results, get the values that match the display name attribute // lpValues = pLDAP->pfnldap_get_values(pld, pMessage, szDisplayName); if (lpValues) { DWORD dwFriendlyLength = lstrlen(*lpValues)+1; pszFriendlyName = (LPWSTR) LocalAlloc( LPTR, (dwFriendlyLength) * sizeof(TCHAR) ); if ( pszFriendlyName == 0) { xe = GetLastError(); DebugMsg((DM_WARNING, TEXT("ProcessGPO: Unable to allocate memory"))); pLDAP->pfnldap_value_free (lpValues); goto Exit; } hr = StringCchCopy (pszFriendlyName, dwFriendlyLength, *lpValues); ASSERT(SUCCEEDED(hr)); DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: Found display name of: <%s>"), pszFriendlyName)); pLDAP->pfnldap_value_free (lpValues); } else { DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: No display name for this object."))); pszFriendlyName = (LPWSTR) LocalAlloc( LPTR, 2 * sizeof(TCHAR) ); if ( pszFriendlyName == 0) { xe = GetLastError(); DebugMsg((DM_WARNING, TEXT("ProcessGPO: Unable to allocate memory"))); goto Exit; } pszFriendlyName[0] = TEXT('\0'); } // // In the results, get the values that match the version attribute // lpValues = pLDAP->pfnldap_get_values(pld, pMessage, szVersion); if (lpValues) { dwVersion = StringToInt (*lpValues); if (dwFlags & GPO_LIST_FLAG_MACHINE) { dwVersion = MAKELONG(LOWORD(dwVersion), LOWORD(dwGPTVersion)); DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: Found machine version of: GPC is %d, GPT is %d"), LOWORD(dwVersion), HIWORD(dwVersion))); } else { dwVersion = MAKELONG(HIWORD(dwVersion), HIWORD(dwGPTVersion)); DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: Found user version of: GPC is %d, GPT is %d"), LOWORD(dwVersion), HIWORD(dwVersion))); } pLDAP->pfnldap_value_free (lpValues); } else { // start treating this as an error. xe = pLDAP->pfnLdapMapErrorToWin32(pLDAP->pfnLdapGetLastError()); DebugMsg((DM_WARNING, TEXT("ProcessGPO: GPO %s does not have a version number."), lpGPOPath)); CEvents ev(TRUE, EVENT_NODSVERSION); ev.AddArg(lpGPOPath); ev.AddArgLdapError(pLDAP->pfnLdapGetLastError()); ev.Report(); goto Exit; } // // In the results, get the values that match the flags attribute // lpValues = pLDAP->pfnldap_get_values(pld, pMessage, szFlags); if (lpValues) { dwGPOFlags = StringToInt (*lpValues); DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: Found flags of: %d"), dwGPOFlags)); pLDAP->pfnldap_value_free (lpValues); } else { DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: No flags for this object."))); } // // In the results, get the values that match the extension names attribute // lpValues = pLDAP->pfnldap_get_values(pld, pMessage, (dwFlags & GPO_LIST_FLAG_MACHINE) ? GPO_MACHEXTENSION_NAMES : GPO_USEREXTENSION_NAMES ); if (lpValues) { if ( lstrcmpi( *lpValues, TEXT(" ") ) == 0 ) { // // A blank char is also a null property case, because Adsi doesn't commit null strings // DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: No client-side extensions for this object."))); } else { DWORD dwExtLength = lstrlen(*lpValues)+1; pszExtensions = (LPWSTR) LocalAlloc( LPTR, (dwExtLength) * sizeof(TCHAR) ); if ( pszExtensions == 0 ) { xe = GetLastError(); DebugMsg((DM_WARNING, TEXT("ProcessGPO: Unable to allocate memory"))); pLDAP->pfnldap_value_free (lpValues); goto Exit; } hr = StringCchCopy( pszExtensions, dwExtLength, *lpValues ); ASSERT(SUCCEEDED(hr)); DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: Found extensions: %s"), pszExtensions)); } pLDAP->pfnldap_value_free (lpValues); } else { DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: No client-side extensions for this object."))); } // // Log which GPO we found // if (bVerbose) { CEvents ev(FALSE, EVENT_FOUND_GPO); ev.AddArg(pszFriendlyName); ev.AddArg(szGPOName); ev.Report(); } // // Check the functionalty version number // if (dwFunctionalityVersion < 2) { DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: GPO %s was created by an old version of the Group Policy Editor. It will be skipped."), pszFriendlyName)); if (bVerbose) { CEvents ev(FALSE, EVENT_GPO_TOO_OLD); ev.AddArg(pszFriendlyName); ev.Report(); } bOldGpoVersion = TRUE; } // // Check if the GPO is disabled // if (((dwFlags & GPO_LIST_FLAG_MACHINE) && (dwGPOFlags & GPO_OPTION_DISABLE_MACHINE)) || (!(dwFlags & GPO_LIST_FLAG_MACHINE) && (dwGPOFlags & GPO_OPTION_DISABLE_USER))) { DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: GPO %s is disabled. It will be skipped."), pszFriendlyName)); if (bVerbose) { CEvents ev(FALSE, EVENT_GPO_DISABLED); ev.AddArg(pszFriendlyName); ev.Report(); } bDisabled = TRUE; } // // Check if the version number is 0, if so there isn't any data // in the GPO and we can skip it // if (dwVersion == 0) { DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: GPO %s doesn't contain any data since the version number is 0. It will be skipped."), pszFriendlyName)); if (bVerbose) { CEvents ev(FALSE, EVENT_GPO_NO_DATA); ev.AddArg(pszFriendlyName); ev.Report(); } bNoGpoData = TRUE; } // // Put the correct container name on the front of the LDAP path // DWORD dwTempLength = lstrlen(lpGPOPath) + 20; lpTemp = (LPWSTR) LocalAlloc (LPTR, (dwTempLength) * sizeof(TCHAR)); if (!lpTemp) { xe = GetLastError(); DebugMsg((DM_WARNING, TEXT("ProcessGPO: Failed to allocate memory with %d"), GetLastError())); CEvents ev(TRUE, EVENT_OUT_OF_MEMORY); ev.AddArgWin32Error(GetLastError()); ev.Report(); goto Exit; } if (dwFlags & GPO_LIST_FLAG_MACHINE) { hr = StringCchCopy (lpTemp, dwTempLength, TEXT("LDAP://CN=Machine,")); } else { hr = StringCchCopy (lpTemp, dwTempLength, TEXT("LDAP://CN=User,")); } ASSERT(SUCCEEDED(hr)); hr = StringCchCat (lpTemp, dwTempLength, lpPath); ASSERT(SUCCEEDED(hr)); // // Add this GPO to the list // if ( bRsopLogging ) { bResult = AddGPOToRsopList( ppGpContainerList, dwFlags, TRUE, bAccessGranted, bDisabled, dwVersion, lpTemp, pszGPTPath, pszFriendlyName, szGPOName, pSD, cbSDLen, bFilterAllowed, pwszFilterId, lpDSObject, dwGPOOptions ); if (!bResult) { xe = GetLastError(); LocalFree(lpTemp); goto Exit; } } if ( bProcessGPO && bAccessGranted && !bOldGpoVersion && !bDisabled && !bNoGpoData && bFilterAllowed) { bResult = AddGPO (lpGPOList, dwFlags, TRUE, bAccessGranted, bDisabled, dwGPOOptions, dwVersion, lpTemp, pszGPTPath, pszFriendlyName, szGPOName, pszExtensions, pSD, cbSDLen, GPOLink, lpDSObject, 0, FALSE, bBlock, bVerbose, bProcessGPO); } if (!bResult) { xe = GetLastError(); DebugMsg((DM_WARNING, TEXT("ProcessGPO: Failed to add GPO <%s> to the list."), pszFriendlyName)); } LocalFree (lpTemp); Exit: if ( pSD ) LocalFree( pSD ); if ( pszGPTPath ) LocalFree( pszGPTPath ); if ( pszFriendlyName ) LocalFree( pszFriendlyName ); if ( pszExtensions ) LocalFree( pszExtensions ); if ( pwszFilterId ) LocalFree( pwszFilterId ); if (pMessage && bOwnLdapMsg ) { pLDAP->pfnldap_msgfree (pMessage); } DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: =============================="))); return bResult; } //************************************************************* // // SearchDSObject() // // Purpose: Searches the specified DS object for GPOs and // if found, adds them to the list. // // Parameters: lpDSObject - DS object to search // dwFlags - GetGPOList & GP_PLANMODE flags // pGPOForcedList - List of forced GPOs // pGPONonForcedList - List of non-forced GPOs // ppSOMList - List of LSDOUs // ppGpContainerList - List of Gp Containers // bVerbose - Verbose output // GPOLink - GPO link type // pld - LDAP info // pLDAP - LDAP api // bBlock - Pointer to the block flag // // // Return: TRUE if successful // FALSE if an error occurs // //************************************************************* BOOL SearchDSObject (LPTSTR lpDSObject, DWORD dwFlags, HANDLE hToken, PGROUP_POLICY_OBJECT *pGPOForcedList, PGROUP_POLICY_OBJECT *pGPONonForcedList, LPSCOPEOFMGMT *ppSOMList, LPGPCONTAINER *ppGpContainerList, BOOL bVerbose, GPO_LINK GPOLink, PLDAP pld, PLDAP_API pLDAP, PLDAPMessage pLDAPMsg,BOOL *bBlock, PRSOPTOKEN pRsopToken ) { PGROUP_POLICY_OBJECT pForced = NULL, pNonForced = NULL, lpGPO; LPTSTR *lpValues; ULONG ulResult; BOOL bResult = FALSE; BOOL bOwnLdapMsg = FALSE; // LDAP message owned by us (if true) or caller (if false) DWORD dwGPOOptions, dwOptions = 0; LPTSTR lpTemp, lpList, lpDSClass; BYTE berValue[8]; LDAPControl SeInfoControl = { LDAP_SERVER_SD_FLAGS_OID_W, { 5, (PCHAR)berValue }, TRUE }; PLDAPControl ServerControls[] = { &SeInfoControl, NULL }; TCHAR szGPLink[] = TEXT("gPLink"); TCHAR szGPOPath[512]; TCHAR szGPOOptions[12]; TCHAR szGPOptions[] = TEXT("gPOptions"); TCHAR szSDProperty[] = TEXT("nTSecurityDescriptor"); ULONG i = 0; LPTSTR lpFullDSObject = NULL; BOOL bFound = FALSE; LPTSTR lpAttr[] = { szGPLink, szGPOptions, // szObjectClass, not needed szSDProperty, NULL }; SCOPEOFMGMT *pSOM = NULL; BOOL bRsopLogging = (ppSOMList != NULL); BOOL bAllGPOs = (dwFlags & FLAG_NO_GPO_FILTER) && (dwFlags & GP_PLANMODE); XLastError xe; HRESULT hr = S_OK; // // Setup the BER encoding for the SD // berValue[0] = 0x30; berValue[1] = 0x03; berValue[2] = 0x02; // denotes an integer berValue[3] = 0x01; // denotes size berValue[4] = (BYTE)((DACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION) & 0xF); if ( !pRsopToken ) { // // if it is not planning mode, don't get the SD // lpAttr[2] = NULL; ServerControls[0] = NULL; } // // Search for the object // DebugMsg((DM_VERBOSE, TEXT("SearchDSObject: Searching <%s>"), lpDSObject)); if (bVerbose) { CEvents ev(FALSE, EVENT_SEARCHING); ev.AddArg(lpDSObject); ev.Report(); } if ( bRsopLogging ) { pSOM = AllocSOM( lpDSObject ); if ( !pSOM ) { xe = GetLastError(); DebugMsg((DM_WARNING, TEXT("SearchDSObject: Unable to allocate memory for SOM object. Leaving. "))); goto Exit; } pSOM->dwType = GPOLink; pSOM->bBlocked = *bBlock; } if ( pLDAPMsg == NULL ) { bOwnLdapMsg = TRUE; ulResult = pLDAP->pfnldap_search_ext_s(pld, lpDSObject, LDAP_SCOPE_BASE, szDSClassAny, lpAttr, FALSE, (PLDAPControl*)ServerControls, NULL, NULL, 0, &pLDAPMsg); if (ulResult != LDAP_SUCCESS) { if (ulResult == LDAP_NO_SUCH_ATTRIBUTE) { DebugMsg((DM_VERBOSE, TEXT("SearchDSObject: No GPO(s) for this object."))); if (bVerbose) { CEvents ev(FALSE, EVENT_NO_GPOS); ev.AddArg(lpDSObject); ev.Report(); } bResult = TRUE; } else if (ulResult == LDAP_NO_SUCH_OBJECT) { DebugMsg((DM_VERBOSE, TEXT("SearchDSObject: Object not found in DS (this is ok). Leaving. "))); if (bVerbose) { CEvents ev(FALSE, EVENT_NO_DS_OBJECT); ev.AddArg(lpDSObject); ev.Report(); } bResult = TRUE; } else if (ulResult == LDAP_SIZELIMIT_EXCEEDED) { xe = pLDAP->pfnLdapMapErrorToWin32(ulResult); DebugMsg((DM_WARNING, TEXT("SearchDSObject: Too many linked GPOs in search.") )); CEvents ev(TRUE, EVENT_TOO_MANY_GPOS); ev.Report(); } else { xe = pLDAP->pfnLdapMapErrorToWin32(ulResult); DebugMsg((DM_VERBOSE, TEXT("SearchDSObject: Failed to find DS object <%s> due to error %d."), lpDSObject, ulResult)); CEvents ev(TRUE, EVENT_GPLINK_NOT_FOUND); ev.AddArg(lpDSObject); ev.AddArgLdapError(ulResult); ev.Report(); } goto Exit; } } if ( bRsopLogging && pRsopToken && !bAllGPOs ) { // // In Rsop planning mode, check access to OU // BOOL bAccessGranted = FALSE; BOOL bOk; bOk = CheckOUAccess(pLDAP, pld, pLDAPMsg, pRsopToken, &bAccessGranted ); if ( !bOk ) { xe = GetLastError(); goto Exit; } if ( !bAccessGranted ) { // // no access for the user on the OU. Exit // DebugMsg((DM_VERBOSE, TEXT("SearchDSObject: Access denied in planning mode to SOM <%s>"), lpDSObject)); if (pLDAPMsg && bOwnLdapMsg ) { pLDAP->pfnldap_msgfree (pLDAPMsg); pLDAPMsg = 0; } CEvents ev(TRUE, EVENT_OU_ACCESSDENIED); ev.AddArg(lpDSObject); ev.Report(); goto Exit; } } // // In the results, get the values that match the gPOptions attribute // lpValues = pLDAP->pfnldap_get_values(pld, pLDAPMsg, szGPOptions); if (lpValues && *lpValues) { dwOptions = StringToInt (*lpValues); pLDAP->pfnldap_value_free (lpValues); } // // In the results, get the values that match the gPLink attribute // lpValues = pLDAP->pfnldap_get_values(pld, pLDAPMsg, szGPLink); if (lpValues && *lpValues) { lpList = *lpValues; DebugMsg((DM_VERBOSE, TEXT("SearchDSObject: Found GPO(s): <%s>"), lpList)); DWORD dwFullLength = lstrlen(lpDSObject) + 8; lpFullDSObject = (LPWSTR) LocalAlloc (LPTR, (dwFullLength) * sizeof(TCHAR)); if (!lpFullDSObject) { xe = GetLastError(); DebugMsg((DM_WARNING, TEXT("SearchDSObject: Failed to allocate memory for full DS Object path name with %d"), GetLastError())); pLDAP->pfnldap_value_free (lpValues); goto Exit; } hr = StringCchCopy (lpFullDSObject, dwFullLength, TEXT("LDAP://")); ASSERT(SUCCEEDED(hr)); hr = StringCchCat (lpFullDSObject, dwFullLength, lpDSObject); ASSERT(SUCCEEDED(hr)); while (*lpList) { DWORD dwLenRemaining; // // Pull off the GPO ldap path // lpTemp = szGPOPath; dwLenRemaining = (ARRAYSIZE(szGPOPath))-1; // (len of array) - (end of string character) dwGPOOptions = 0; while (*lpList && (*lpList != TEXT('['))) { lpList++; } if (!(*lpList)) { break; } lpList++; while ((dwLenRemaining) && *lpList && (*lpList != TEXT(';'))) { *lpTemp++ = *lpList++; dwLenRemaining--; } if (*lpList != TEXT(';')) { break; } *lpTemp = TEXT('\0'); lpList++; lpTemp = szGPOOptions; dwLenRemaining = (ARRAYSIZE(szGPOOptions))-1; // (len of array) - (end of string character) *lpTemp = TEXT('\0'); while ((dwLenRemaining) && *lpList && (*lpList != TEXT(']'))) { *lpTemp++ = *lpList++; dwLenRemaining--; } if (*lpList != TEXT(']')) { break; } *lpTemp = TEXT('\0'); lpList++; dwGPOOptions = StringToInt (szGPOOptions); if ( bRsopLogging ) { GPLINK *pGpLink = AllocGpLink( szGPOPath, dwGPOOptions ); if ( pGpLink == NULL ) { xe = GetLastError(); DebugMsg((DM_WARNING, TEXT("SearchDSObject: Unable to allocate memory for GpLink object. Leaving. "))); goto Exit; } // // Append GpLink to end of SOM list // if ( pSOM->pGpLinkList == NULL ) { pSOM->pGpLinkList = pGpLink; } else { GPLINK *pTrailPtr = NULL; GPLINK *pCurPtr = pSOM->pGpLinkList; while ( pCurPtr != NULL ) { pTrailPtr = pCurPtr; pCurPtr = pCurPtr->pNext; } pTrailPtr->pNext = pGpLink; } } // // Check if this link is disabled // BOOL bProcessGPO = TRUE; if ( ( dwGPOOptions & GPO_FLAG_DISABLE ) && !bAllGPOs ) { DebugMsg((DM_VERBOSE, TEXT("SearchDSObject: The link to GPO %s is disabled. It will be skipped for processing."), szGPOPath)); if (bVerbose) { CEvents ev(FALSE, EVENT_GPO_LINK_DISABLED); ev.AddArg(szGPOPath); ev.Report(); } bProcessGPO = FALSE; } if (bProcessGPO || (dwFlags & GP_PLANMODE)) { if (!bProcessGPO) { DebugMsg((DM_VERBOSE, TEXT("SearchDSObject: The link to GPO %s is disabled. GPO is still being queried. Planning mode."), szGPOPath)); } if ( !ProcessGPO( szGPOPath, dwFlags, hToken, (dwGPOOptions & GPO_FLAG_FORCE) ? &pForced : &pNonForced, ppGpContainerList, dwGPOOptions, TRUE, bVerbose, GPOLink, lpFullDSObject, pld, pLDAP, 0, *bBlock, pRsopToken, 0, 0, bProcessGPO ) ) { xe = GetLastError(); DebugMsg((DM_WARNING, TEXT("SearchDSObject: ProcessGPO failed."))); pLDAP->pfnldap_value_free (lpValues); goto Exit; } } } pLDAP->pfnldap_value_free (lpValues); // // Set the block flag now if requested. This way OU's, domains, etc // higher in the namespace will have GPOs removed if appropriate // if (dwOptions & GPC_BLOCK_POLICY) { *bBlock = TRUE; if ( bRsopLogging ) pSOM->bBlocking = TRUE; DebugMsg((DM_VERBOSE, TEXT("SearchDSObject: <%s> has the Block From Above attribute set"), lpDSObject)); if (bVerbose) { CEvents ev(FALSE, EVENT_BLOCK_ENABLED); ev.AddArg(lpDSObject); ev.Report(); } } } else { DebugMsg((DM_VERBOSE, TEXT("SearchDSObject: No GPO(s) for this object."))); if (bVerbose) { CEvents ev(FALSE, EVENT_NO_GPOS); ev.AddArg(lpDSObject); ev.Report(); } } // // Merge the temp and real lists together // First the non-forced lists // if (pNonForced) { lpGPO = pNonForced; while (lpGPO->pNext) { lpGPO = lpGPO->pNext; } lpGPO->pNext = *pGPONonForcedList; if (*pGPONonForcedList) { (*pGPONonForcedList)->pPrev = lpGPO; } *pGPONonForcedList = pNonForced; } // // Now the forced lists // if (pForced) { lpGPO = *pGPOForcedList; if (lpGPO) { while (lpGPO->pNext) { lpGPO = lpGPO->pNext; } lpGPO->pNext = pForced; pForced->pPrev = lpGPO; } else { *pGPOForcedList = pForced; } } bResult = TRUE; Exit: if ( !bResult && pSOM != NULL ) { FreeSOM( pSOM ); } else { if ( bResult && bRsopLogging ) { // // Insert SOM at the beginning // pSOM->pNext = *ppSOMList; *ppSOMList = pSOM; } } if (lpFullDSObject) { LocalFree (lpFullDSObject); } if (pLDAPMsg && bOwnLdapMsg ) { pLDAP->pfnldap_msgfree (pLDAPMsg); } return bResult; } //************************************************************* // // AllocDnEntry() // // Purpose: Allocates a new struct for dn entry // // // Parameters: pwszDN - Distinguished name // // Return: Pointer if successful // NULL if an error occurs // //************************************************************* DNENTRY * AllocDnEntry( LPTSTR pwszDN ) { DNENTRY *pDnEntry = (DNENTRY *) LocalAlloc (LPTR, sizeof(DNENTRY)); XLastError xe; HRESULT hr = S_OK; if ( pDnEntry == NULL ) { xe = GetLastError(); DebugMsg((DM_WARNING, TEXT("AllocDnEntry: Failed to alloc pDnEntry with 0x%x."), GetLastError())); return NULL; } pDnEntry->pwszDN = (LPTSTR) LocalAlloc (LPTR, (lstrlen(pwszDN) + 1) * sizeof(TCHAR) ); if ( pDnEntry->pwszDN == NULL ) { xe = GetLastError(); DebugMsg((DM_WARNING, TEXT("AllocDnEntry: Failed to alloc pwszDN with 0x%x."), GetLastError())); LocalFree( pDnEntry ); return NULL; } hr = StringCchCopy( pDnEntry->pwszDN, lstrlen(pwszDN) + 1, pwszDN ); ASSERT(SUCCEEDED(hr)); return pDnEntry; } //************************************************************* // // FreeDnEntry() // // Purpose: Frees dn entry struct // //************************************************************* void FreeDnEntry( DNENTRY *pDnEntry ) { if ( pDnEntry ) { if ( pDnEntry->pwszDN ) LocalFree( pDnEntry->pwszDN ); LocalFree( pDnEntry ); } } //************************************************************* // // AllocLdapQuery() // // Purpose: Allocates a new struct for ldap query // // // Parameters: pwszDomain - Domain of Gpo // // Return: Pointer if successful // NULL if an error occurs // //************************************************************* LDAPQUERY * AllocLdapQuery( LPTSTR pwszDomain ) { const INIT_ALLOC_SIZE = 1000; LDAPQUERY *pQuery = (LDAPQUERY *) LocalAlloc (LPTR, sizeof(LDAPQUERY)); XLastError xe; HRESULT hr = S_OK; if ( pQuery == NULL ) { xe = GetLastError(); DebugMsg((DM_WARNING, TEXT("AllocLdapQuery: Failed to alloc pQuery with 0x%x."), GetLastError())); return NULL; } pQuery->pwszDomain = (LPTSTR) LocalAlloc (LPTR, (lstrlen(pwszDomain) + 1) * sizeof(TCHAR) ); if ( pQuery->pwszDomain == NULL ) { xe = GetLastError(); DebugMsg((DM_WARNING, TEXT("AllocLdapQuery: Failed to alloc pwszDomain with 0x%x."), GetLastError())); LocalFree( pQuery ); return NULL; } pQuery->pwszFilter = (LPTSTR) LocalAlloc (LPTR, INIT_ALLOC_SIZE ); if ( pQuery->pwszFilter == NULL ) { xe = GetLastError(); DebugMsg((DM_WARNING, TEXT("AllocLdapQuery: Failed to alloc pwszFilter with 0x%x."), GetLastError())); LocalFree( pQuery->pwszDomain ); LocalFree( pQuery ); return NULL; } hr = StringCchCopy( pQuery->pwszDomain, lstrlen(pwszDomain) + 1, pwszDomain ); ASSERT(SUCCEEDED(hr)); hr = StringCchCopy( pQuery->pwszFilter, INIT_ALLOC_SIZE, L"(|)" ); ASSERT(SUCCEEDED(hr)); pQuery->cbLen = 8; // 8 = (lstrlen(L"(|)") + 1) * sizeof(TCHAR) pQuery->cbAllocLen = INIT_ALLOC_SIZE; return pQuery; } //************************************************************* // // FreeLdapQuery() // // Purpose: Frees ldap query struct // //************************************************************* void FreeLdapQuery( PLDAP_API pLDAP, LDAPQUERY *pQuery ) { DNENTRY *pDnEntry = NULL; if ( pQuery ) { if ( pQuery->pwszDomain ) LocalFree( pQuery->pwszDomain ); if ( pQuery->pwszFilter ) LocalFree( pQuery->pwszFilter ); if ( pQuery->pMessage ) pLDAP->pfnldap_msgfree( pQuery->pMessage ); if ( pQuery->pLdapHandle && pQuery->bOwnLdapHandle ) pLDAP->pfnldap_unbind( pQuery->pLdapHandle ); pDnEntry = pQuery->pDnEntry; while ( pDnEntry ) { DNENTRY *pTemp = pDnEntry->pNext; FreeDnEntry( pDnEntry ); pDnEntry = pTemp; } LocalFree( pQuery ); } } //************************************************************* // // MatchDnWithDeferredItems() // // Purpose: Matches the dns from ldap query with the deferred items // // Parameters: pLDAP - LDAP function table pointer // ppLdapQuery - LDAP query list // // Return: TRUE if successful // FALSE if an error occurs // //************************************************************* BOOL MatchDnWithDeferredItems( PLDAP_API pLDAP, LDAPQUERY *pLdapQuery, BOOL bOUProcessing ) { PLDAPMessage pMsg = pLDAP->pfnldap_first_entry( pLdapQuery->pLdapHandle, pLdapQuery->pMessage ); while ( pMsg ) { WCHAR *pwszDN = pLDAP->pfnldap_get_dn( pLdapQuery->pLdapHandle, pMsg ); // fixing bug 568263 if (!pwszDN) { return FALSE; } DNENTRY *pCurPtr = pLdapQuery->pDnEntry; while ( pCurPtr ) { INT iResult = CompareString ( LOCALE_INVARIANT, NORM_IGNORECASE, pwszDN, -1, pCurPtr->pwszDN, -1 ); if ( iResult == CSTR_EQUAL ) { // // Store the pointer to ldap message so that it can be used // later to retrieve necessary attributes. // if ( bOUProcessing ) pCurPtr->pDeferredOU->pOUMsg = pMsg; else { LPGPOPROCDATA lpGpoProcData = (LPGPOPROCDATA)pCurPtr->pDeferredGPO->lParam2; pCurPtr->pDeferredGPO->lParam = (LPARAM) pMsg; lpGpoProcData->pLdapHandle = pLdapQuery->pLdapHandle; } pCurPtr = pCurPtr->pNext; } else if ( iResult == CSTR_LESS_THAN ) { // // Since dns are in ascending order, // we are done. // break; } else { // // Advance down the list // pCurPtr = pCurPtr->pNext; } // final else } // while pcurptr pLDAP->pfnldap_memfree( pwszDN ); pMsg = pLDAP->pfnldap_next_entry( pLdapQuery->pLdapHandle, pMsg ); } // while pmsg return TRUE; } LPWSTR DsQuoteSearchFilter( LPCWSTR ); //************************************************************* // // AddDnToFilter() // // Purpose: ORs in the new dn to the ldap filter // // Parameters: ppLdapQuery - LDAP query list // pGPO - Deferred GPO // // Return: TRUE if successful // FALSE if an error occurs // //************************************************************* BOOL AddDnToFilter( LDAPQUERY *pLdapQuery, LPTSTR pwszDN ) { const DN_SIZE = 20; // 20 = # chars in "(dis..=)" BOOL bSuccess = FALSE; LPWSTR szQuotedDN; HRESULT hr = S_OK; szQuotedDN = DsQuoteSearchFilter( pwszDN ); if ( ! szQuotedDN ) { DebugMsg((DM_WARNING, TEXT("GetGPOInfo: DsQuoteSearchFilter failed with = <%d>"), GetLastError() )); goto AddDnToFilter_ExitAndCleanup; } DWORD cbNew = (lstrlen(szQuotedDN) + DN_SIZE) * sizeof(TCHAR); // + 1 is not needed because \0 is already part of filter string DWORD cbSizeRequired = pLdapQuery->cbLen + cbNew; if ( cbSizeRequired >= pLdapQuery->cbAllocLen ) { // // Need to grow buffer because of overflow // LPTSTR pwszNewFilter = (LPTSTR) LocalAlloc (LPTR, cbSizeRequired * 2); if ( pwszNewFilter == NULL ) { DebugMsg((DM_WARNING, TEXT("AddDnToFilter: Unable to allocate new filter string") )); goto AddDnToFilter_ExitAndCleanup; } hr = StringCchCopy( pwszNewFilter, cbSizeRequired, pLdapQuery->pwszFilter ); ASSERT(SUCCEEDED(hr)); LocalFree( pLdapQuery->pwszFilter ); pLdapQuery->pwszFilter = pwszNewFilter; pLdapQuery->cbAllocLen = cbSizeRequired * 2; } DmAssert( cbSizeRequired < pLdapQuery->cbAllocLen ); // // Overwrite last ")" and then append the new dn name term // hr = StringCchCopy( &pLdapQuery->pwszFilter[pLdapQuery->cbLen/sizeof(WCHAR) - 2], (pLdapQuery->cbAllocLen - pLdapQuery->cbLen)/sizeof(WCHAR) + 2, L"(distinguishedName=" ); ASSERT(SUCCEEDED(hr)); hr = StringCchCat( pLdapQuery->pwszFilter, pLdapQuery->cbAllocLen/sizeof(WCHAR), szQuotedDN ); ASSERT(SUCCEEDED(hr)); hr = StringCchCat( pLdapQuery->pwszFilter, pLdapQuery->cbAllocLen/sizeof(WCHAR), L"))" ); ASSERT(SUCCEEDED(hr)); pLdapQuery->cbLen += cbNew; bSuccess = TRUE; AddDnToFilter_ExitAndCleanup: if ( szQuotedDN ) { LocalFree( szQuotedDN ); } return bSuccess; } //************************************************************* // // InsertDN() // // Purpose: Adds a distinguished name entry to ldap query's // names linked list // // Parameters: ppLdapQuery - LDAP query list // pwszDN - DN // pDeferredOU - Deferred OU // pDeferredGPO - Deferred GPO // // Return: TRUE if successful // FALSE if an error occurs // //************************************************************* BOOL InsertDN( LDAPQUERY *pLdapQuery, LPTSTR pwszDN, DNENTRY *pDeferredOU, PGROUP_POLICY_OBJECT pDeferredGPO ) { DNENTRY *pNewEntry = NULL; DNENTRY *pTrailPtr = NULL; DNENTRY *pCurPtr = pLdapQuery->pDnEntry; XLastError xe; DmAssert( !( pDeferredOU && pDeferredGPO ) ); while ( pCurPtr != NULL ) { INT iResult = CompareString ( LOCALE_INVARIANT, NORM_IGNORECASE, pwszDN, -1, pCurPtr->pwszDN, -1 ); if ( iResult == CSTR_EQUAL || iResult == CSTR_LESS_THAN ) { // // Duplicate or since dn's are in ascending order, add new entry // pNewEntry = AllocDnEntry( pwszDN ); if ( pNewEntry == NULL ) return FALSE; if ( !AddDnToFilter( pLdapQuery, pwszDN ) ) { xe = GetLastError(); FreeDnEntry( pNewEntry ); return FALSE; } if ( pDeferredOU ) pNewEntry->pDeferredOU = pDeferredOU; else pNewEntry->pDeferredGPO = pDeferredGPO; pNewEntry->pNext = pCurPtr; if ( pTrailPtr == NULL ) pLdapQuery->pDnEntry = pNewEntry; else pTrailPtr->pNext = pNewEntry; return TRUE; } else { // // Advance down the list // pTrailPtr = pCurPtr; pCurPtr = pCurPtr->pNext; } } // while // // Null list or end of list case. // pNewEntry = AllocDnEntry( pwszDN ); if ( pNewEntry == NULL ) { xe = GetLastError(); return FALSE; } if ( !AddDnToFilter( pLdapQuery, pwszDN ) ) { xe = GetLastError(); FreeDnEntry( pNewEntry ); return FALSE; } if ( pDeferredOU ) pNewEntry->pDeferredOU = pDeferredOU; else pNewEntry->pDeferredGPO = pDeferredGPO; pNewEntry->pNext = pCurPtr; if ( pTrailPtr == NULL ) pLdapQuery->pDnEntry = pNewEntry; else pTrailPtr->pNext = pNewEntry; return TRUE; } //************************************************************* // // AddDN() // // Purpose: Adds a distinguished name entry to ldap query // // Parameters: ppLdapQuery - LDAP query list // pwszDN - DN name // pDeferredOU - Deferred OU // pDeferredGPO - Deferred GPO // // Return: TRUE if successful // FALSE if an error occurs // //************************************************************* BOOL AddDN( PLDAP_API pLDAP, LDAPQUERY **ppLdapQuery, LPTSTR pwszDN, DNENTRY *pDeferredOU, PGROUP_POLICY_OBJECT pDeferredGPO ) { LPTSTR pwszDomain = NULL; LPTSTR pwszTemp = pwszDN; LDAPQUERY *pNewQuery = NULL; LDAPQUERY *pTrailPtr = NULL; LDAPQUERY *pCurPtr = *ppLdapQuery; XLastError xe; DmAssert( !( pDeferredOU && pDeferredGPO ) ); // // Find the domain to which the GPO belongs // if ( pwszTemp == NULL ) { DebugMsg((DM_WARNING, TEXT("AddDN: Null pwszDN. Exiting.") )); return FALSE; } while ( *pwszTemp ) { // // The check below needs to be more sophisticated to take care // of spaces in names etc. // if (CompareString ( LOCALE_INVARIANT, NORM_IGNORECASE, pwszTemp, 16, TEXT("cn=configuration"), 16) == CSTR_EQUAL ) { DebugMsg((DM_VERBOSE, TEXT("AddDN: DN %s is under cn=configuration container. queueing for rebinding"), pwszDN )); pwszDomain = pwszTemp; break; } if (CompareString ( LOCALE_INVARIANT, NORM_IGNORECASE, pwszTemp, 3, TEXT("DC="), 3) == CSTR_EQUAL ) { pwszDomain = pwszTemp; break; } // // Move to the next chunk of the DN name // while ( *pwszTemp && (*pwszTemp != TEXT(','))) pwszTemp++; if ( *pwszTemp == TEXT(',')) pwszTemp++; } if ( pwszDomain == NULL ) { xe = ERROR_INVALID_DATA; DebugMsg((DM_WARNING, TEXT("AddDN: Domain not found for <%s>. Exiting."), pwszDN )); return FALSE; } while ( pCurPtr != NULL ) { INT iResult = CompareString ( LOCALE_INVARIANT, NORM_IGNORECASE, pwszDomain, -1, pCurPtr->pwszDomain, -1 ); if ( iResult == CSTR_EQUAL ) { BOOL bOk = InsertDN( pCurPtr, pwszDN, pDeferredOU, pDeferredGPO ); return bOk; } else if ( iResult == CSTR_LESS_THAN ) { // // Since domains are in ascending order, // pwszDomain is not in list, so add. // pNewQuery = AllocLdapQuery( pwszDomain ); if ( pNewQuery == NULL ) { xe = GetLastError(); return FALSE; } if ( !InsertDN( pNewQuery, pwszDN, pDeferredOU, pDeferredGPO ) ) { xe = GetLastError(); FreeLdapQuery( pLDAP, pNewQuery ); return FALSE; } pNewQuery->pNext = pCurPtr; if ( pTrailPtr == NULL ) *ppLdapQuery = pNewQuery; else pTrailPtr->pNext = pNewQuery; return TRUE; } else { // // Advance down the list // pTrailPtr = pCurPtr; pCurPtr = pCurPtr->pNext; } } // while // // Null list or end of list case. // pNewQuery = AllocLdapQuery( pwszDomain ); if ( pNewQuery == NULL ) { xe = GetLastError(); return FALSE; } if ( !InsertDN( pNewQuery, pwszDN, pDeferredOU, pDeferredGPO ) ) { xe = GetLastError(); FreeLdapQuery( pLDAP, pNewQuery ); return FALSE; } pNewQuery->pNext = pCurPtr; if ( pTrailPtr == NULL ) *ppLdapQuery = pNewQuery; else pTrailPtr->pNext = pNewQuery; return TRUE; } //************************************************************* // // EvalList() // // Purpose: Encapsulates common processing functionality for // forced and nonforced lists // // Parameters: pLDAP - LDAP api // dwFlags - GetGPOList flags // bVerbose - Verbose flag // hToken - User or machine token // pDeferredList - List of deferred GPOs // ppGPOList - List of evaluated GPOs // ppGpContainerList - List of Gp Containers // pGpoFilter - Gpo filter // pLocator - WMI interfaces // // Return: TRUE if successful // FALSE if an error occurs // //************************************************************* BOOL EvalList( PLDAP_API pLDAP, DWORD dwFlags, HANDLE hToken, BOOL bVerbose, PGROUP_POLICY_OBJECT pDeferredList, PGROUP_POLICY_OBJECT *ppGPOList, LPGPCONTAINER *ppGpContainerList, PRSOPTOKEN pRsopToken, CGpoFilter *pGpoFilter, CLocator *pLocator ) { PGROUP_POLICY_OBJECT pGPOTemp = pDeferredList; while ( pGPOTemp ) { PLDAPMessage pGPOMsg = (PLDAPMessage) pGPOTemp->lParam; if ( pGPOMsg == NULL ) { DebugMsg((DM_VERBOSE, TEXT("EvalList: Object <%s> cannot be accessed"), pGPOTemp->lpDSPath )); if (dwFlags & GP_PLANMODE) { CEvents ev(TRUE, EVENT_OBJECT_NOT_FOUND_PLANNING); ev.AddArg(pGPOTemp->lpDSPath); ev.Report(); } else { if (bVerbose) { CEvents ev(FALSE, EVENT_OBJECT_NOT_FOUND); ev.AddArg(pGPOTemp->lpDSPath); ev.AddArg((DWORD)0); ev.Report(); } } } else { DmAssert( pGPOTemp->lParam2 != NULL ); DmAssert( ((LPGPOPROCDATA)(pGPOTemp->lParam2))->pLdapHandle != NULL ); if ( !ProcessGPO( pGPOTemp->lpDSPath, dwFlags, hToken, ppGPOList, ppGpContainerList, pGPOTemp->dwOptions, FALSE, bVerbose, pGPOTemp->GPOLink, pGPOTemp->lpLink, ((LPGPOPROCDATA)(pGPOTemp->lParam2))->pLdapHandle, pLDAP, pGPOMsg, FALSE, pRsopToken, pGpoFilter, pLocator, ((LPGPOPROCDATA)(pGPOTemp->lParam2))->bProcessGPO ) ) { DebugMsg((DM_WARNING, TEXT("EvalList: ProcessGPO failed") )); return FALSE; } } pGPOTemp = pGPOTemp->pNext; } return TRUE; } //************************************************************* // // EvaluateDeferredGPOs() // // Purpose: Uses a single ldap query to evaluate deferred // GPO lists. // // Parameters: pldBound - Bound LDAP handle // pLDAP - LDAP api // pwszDomainBound - Domain already bound to // dwFlags - GetGPOList flags // hToken - User or machine token // pDeferredForcedList - List of deferred forced GPOs // pDeferredNonForcedList - List of deferred non-forced GPOs // pGPOForcedList - List of forced GPOs // pGPONonForcedList - List of non-forced GPOs // ppGpContainerList - List of Gp Containers // pGpoFilter - Gpo filter // pLocator - WMI interfaces // // Return: TRUE if successful // FALSE if an error occurs // //************************************************************* BOOL EvaluateDeferredGPOs (PLDAP pldBound, PLDAP_API pLDAP, LPTSTR pwszDomainBound, DWORD dwFlags, HANDLE hToken, BOOL bVerbose, PGROUP_POLICY_OBJECT pDeferredForcedList, PGROUP_POLICY_OBJECT pDeferredNonForcedList, PGROUP_POLICY_OBJECT *ppForcedList, PGROUP_POLICY_OBJECT *ppNonForcedList, LPGPCONTAINER *ppGpContainerList, PRSOPTOKEN pRsopToken, CGpoFilter *pGpoFilter, CLocator *pLocator ) { ULONG ulResult; BOOL bResult = FALSE; BYTE berValue[8]; LDAPControl SeInfoControl = { LDAP_SERVER_SD_FLAGS_OID_W, { 5, (PCHAR)berValue }, TRUE }; LDAPControl referralControl = { LDAP_SERVER_DOMAIN_SCOPE_OID_W, { 0, NULL}, TRUE }; PLDAPControl ServerControls[] = { &SeInfoControl, &referralControl, NULL }; TCHAR szSDProperty[] = TEXT("nTSecurityDescriptor"); TCHAR szCommonName[] = TEXT("cn"); TCHAR szDisplayName[] = TEXT("displayName"); TCHAR szFileSysPath[] = TEXT("gPCFileSysPath"); TCHAR szVersion[] = TEXT("versionNumber"); TCHAR szFunctionalityVersion[] = GPO_FUNCTIONALITY_VERSION; TCHAR szFlags[] = TEXT("flags"); TCHAR szWmiFilter[] = TEXT("gPCWQLFilter"); PWSTR rgAttribs[12] = {szSDProperty, szFileSysPath, szCommonName, szDisplayName, szVersion, szFunctionalityVersion, szFlags, GPO_MACHEXTENSION_NAMES, GPO_USEREXTENSION_NAMES, szObjectClass, szWmiFilter, NULL }; PGROUP_POLICY_OBJECT pGPOTemp = pDeferredForcedList; LDAPQUERY *pLdapQuery = NULL, *pQuery = NULL; VOID *pData; PDS_API pdsApi; BOOL bRsopPlanningMode = (pRsopToken != 0); BOOL bConfigContainer = FALSE; *ppForcedList = NULL; *ppNonForcedList = NULL; XLastError xe; if ( pDeferredForcedList == NULL && pDeferredNonForcedList == NULL ) return TRUE; // // Demand load ntdsapi.dll // pdsApi = LoadDSApi(); if ( pdsApi == 0 ) { xe = GetLastError(); DebugMsg((DM_WARNING, TEXT("EvaluateDeferredGpos: Failed to load ntdsapi.dll"))); goto Exit; } while ( pGPOTemp ) { if ( !AddDN( pLDAP, &pLdapQuery, pGPOTemp->lpDSPath, NULL, pGPOTemp ) ) { xe = GetLastError(); goto Exit; } pGPOTemp = pGPOTemp->pNext; } pGPOTemp = pDeferredNonForcedList; while ( pGPOTemp ) { if ( !AddDN( pLDAP, &pLdapQuery, pGPOTemp->lpDSPath, NULL, pGPOTemp ) ) { xe = GetLastError(); goto Exit; } pGPOTemp = pGPOTemp->pNext; } // // Setup the BER encoding // berValue[0] = 0x30; berValue[1] = 0x03; berValue[2] = 0x02; // denotes an integer berValue[3] = 0x01; // denotes size berValue[4] = (BYTE)((DACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION) & 0xF); pQuery = pLdapQuery; while ( pQuery ) { // // The check below needs to be more sophisticated to take care // of spaces in names etc. // // It is assumed that the configuration // container would be common across the whole forest and will // not need a new bind.. // if (CompareString ( LOCALE_INVARIANT, NORM_IGNORECASE, pQuery->pwszDomain, 16, TEXT("cn=configuration"), 16) == CSTR_EQUAL ) { DebugMsg((DM_VERBOSE, TEXT("EvaluateDeferredGPOs: DN %s is under cn=configuration container"), pQuery->pwszDomain )); bConfigContainer = TRUE; } else bConfigContainer = FALSE; // // Check if this is a cross-domain Gpo and hence needs a new bind // WCHAR *pDomainString[1]; PDS_NAME_RESULT pNameResult = NULL; PLDAP pLdapHandle = NULL; if (!bConfigContainer) pDomainString[0] = pQuery->pwszDomain; else { DebugMsg((DM_VERBOSE, TEXT("EvaluateDeferredGPOs: The GPO is under the config container. Querying seperately\n"))); // // This is a configuration container and we have to figure // out the domain name still.. // LPTSTR pwszTemp = pQuery->pwszDomain; pDomainString[0] = NULL; while ( *pwszTemp ) { if (CompareString ( LOCALE_INVARIANT, NORM_IGNORECASE, pwszTemp, 3, TEXT("DC="), 3) == CSTR_EQUAL ) { pDomainString[0] = pwszTemp; break; } // // Move to the next chunk of the DN name // while ( *pwszTemp && (*pwszTemp != TEXT(','))) pwszTemp++; if ( *pwszTemp == TEXT(',')) pwszTemp++; } if ( pDomainString[0] == NULL ) { xe = ERROR_INVALID_DATA; DebugMsg((DM_WARNING, TEXT("EvaluateDeferredGPOs: Domain not found for <%s>. Exiting."), pQuery->pwszDomain )); goto Exit; } } ulResult = pdsApi->pfnDsCrackNames( (HANDLE) -1, DS_NAME_FLAG_SYNTACTICAL_ONLY, DS_FQDN_1779_NAME, DS_CANONICAL_NAME, 1, pDomainString, &pNameResult ); if ( ulResult != ERROR_SUCCESS || pNameResult->cItems == 0 || pNameResult->rItems[0].status != ERROR_SUCCESS || pNameResult->rItems[0].pDomain == NULL ) { xe = ulResult; DebugMsg((DM_VERBOSE, TEXT("EvaluateDeferredGPOs: DsCrackNames failed with 0x%x."), ulResult )); goto Exit; } // // Optimize same domain Gpo queries by not doing an unnecessary bind // pQuery->pLdapHandle = pldBound; if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE, pwszDomainBound, -1, pNameResult->rItems[0].pDomain, -1) != CSTR_EQUAL) { // // Cross-domain Gpo query and so need to bind to new domain // DebugMsg((DM_VERBOSE, TEXT("EvaluateDeferredGPOs: Doing an ldap bind to cross-domain <%s>"), pNameResult->rItems[0].pDomain)); pLdapHandle = pLDAP->pfnldap_init( pNameResult->rItems[0].pDomain, LDAP_PORT); if (!pLdapHandle) { xe = pLDAP->pfnLdapMapErrorToWin32(pLDAP->pfnLdapGetLastError()); DebugMsg((DM_WARNING, TEXT("EvaluateDeferredGPOs: ldap_init for <%s> failed with = 0x%x or %d"), pNameResult->rItems[0].pDomain, pLDAP->pfnLdapGetLastError(), GetLastError())); CEvents ev(TRUE, EVENT_FAILED_DS_INIT); ev.AddArg(pNameResult->rItems[0].pDomain); ev.AddArgLdapError(pLDAP->pfnLdapGetLastError()); ev.Report(); pdsApi->pfnDsFreeNameResult( pNameResult ); goto Exit; } // // Turn on Packet integrity flag // pData = (VOID *) LDAP_OPT_ON; ulResult = pLDAP->pfnldap_set_option(pLdapHandle, LDAP_OPT_SIGN, &pData); if (ulResult != LDAP_SUCCESS) { xe = pLDAP->pfnLdapMapErrorToWin32(ulResult); DebugMsg((DM_WARNING, TEXT("EvaluateDeferredGPOs: Failed to turn on LDAP_OPT_SIGN with %d"), ulResult)); pdsApi->pfnDsFreeNameResult( pNameResult ); pLDAP->pfnldap_unbind(pLdapHandle); pLdapHandle = 0; goto Exit; } ulResult = pLDAP->pfnldap_connect(pLdapHandle, 0); if (ulResult != LDAP_SUCCESS) { CEvents ev(TRUE, EVENT_FAILED_DS_CONNECT); ev.AddArg(pNameResult->rItems[0].pDomain); ev.AddArgLdapError(ulResult); ev.Report(); xe = pLDAP->pfnLdapMapErrorToWin32(ulResult); DebugMsg((DM_WARNING, TEXT("EvaluateDeferredGPOs: Failed to connect with %d"), ulResult)); pdsApi->pfnDsFreeNameResult( pNameResult ); pLDAP->pfnldap_unbind(pLdapHandle); pLdapHandle = 0; goto Exit; } // // Transfer ownerhip of ldap handle to pQuery struct // pQuery->pLdapHandle = pLdapHandle; pQuery->bOwnLdapHandle = TRUE; if ( !bRsopPlanningMode && (dwFlags & GPO_LIST_FLAG_MACHINE) ) { // // For machine policies specifically ask for Kerberos as the only authentication // mechanism. Otherwise if Kerberos were to fail for some reason, then NTLM is used // and localsystem context has no real credentials, which means that we won't get // any GPOs back. // SEC_WINNT_AUTH_IDENTITY_EXW secIdentity; secIdentity.Version = SEC_WINNT_AUTH_IDENTITY_VERSION; secIdentity.Length = sizeof(SEC_WINNT_AUTH_IDENTITY_EXW); secIdentity.User = 0; secIdentity.UserLength = 0; secIdentity.Domain = 0; secIdentity.DomainLength = 0; secIdentity.Password = 0; secIdentity.PasswordLength = 0; secIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; secIdentity.PackageList = wszKerberos; secIdentity.PackageListLength = lstrlen( wszKerberos ); ulResult = pLDAP->pfnldap_bind_s (pLdapHandle, NULL, (WCHAR *)&secIdentity, LDAP_AUTH_SSPI); } else ulResult = pLDAP->pfnldap_bind_s (pLdapHandle, NULL, NULL, LDAP_AUTH_SSPI); if (ulResult != LDAP_SUCCESS) { xe = pLDAP->pfnLdapMapErrorToWin32(ulResult); DebugMsg((DM_WARNING, TEXT("EvaluateDeferredGPOs: ldap_bind_s failed with = <%d>"), ulResult)); CEvents ev(TRUE, EVENT_FAILED_DS_BIND); ev.AddArg(pNameResult->rItems[0].pDomain); ev.AddArgLdapError(ulResult); ev.Report(); pdsApi->pfnDsFreeNameResult( pNameResult ); goto Exit; } DebugMsg((DM_VERBOSE, TEXT("EvaluateDeferredGPOs: Bind sucessful"))); } pdsApi->pfnDsFreeNameResult( pNameResult ); // // Turn referrals off because this is a single domain call // pData = (VOID *) LDAP_OPT_OFF; ulResult = pLDAP->pfnldap_set_option( pQuery->pLdapHandle, LDAP_OPT_REFERRALS, &pData ); if ( ulResult != LDAP_SUCCESS ) { xe = pLDAP->pfnLdapMapErrorToWin32(ulResult); DebugMsg((DM_WARNING, TEXT("EvalauteDeferredGPOs: Failed to turn off referrals with error %d"), ulResult)); goto Exit; } // // Search for GPOs // // // restrict the search to just the policies container // DmAssert( pQuery->pwszDomain != NULL && pQuery->pwszFilter != NULL ); XPtrLF xszGPOSearchBase; DWORD cChLen; cChLen = (1+lstrlen(pQuery->pwszDomain)+lstrlen(DOMAIN_GPO_LOCATION_FMT)); xszGPOSearchBase = (LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR)*cChLen); if (!xszGPOSearchBase) { xe = GetLastError(); DebugMsg((DM_WARNING, TEXT("EvalauteDeferredGPOs: Failed to allocate memory for GPO base search with %d"), GetLastError())); goto Exit; } HRESULT hr; hr = StringCchPrintf(xszGPOSearchBase, cChLen, DOMAIN_GPO_LOCATION_FMT, pQuery->pwszDomain); DmAssert(SUCCEEDED(hr)); DebugMsg((DM_VERBOSE, TEXT("EvaluateDeferredGPOs: Searching for GPOs in %s"), (LPWSTR)xszGPOSearchBase)); ulResult = pLDAP->pfnldap_search_ext_s(pQuery->pLdapHandle, (LPWSTR)xszGPOSearchBase, LDAP_SCOPE_SUBTREE, pQuery->pwszFilter, rgAttribs, 0, (PLDAPControl*)ServerControls, NULL, NULL, 0x10000, &pQuery->pMessage); // // If the search fails, store the error code and return // if (ulResult != LDAP_SUCCESS) { if (ulResult == LDAP_NO_SUCH_ATTRIBUTE) { DebugMsg((DM_VERBOSE, TEXT("EvaluateDeferredGPOs: All objects can not be accessed."))); if (dwFlags & GP_PLANMODE) { CEvents ev(TRUE, EVENT_NO_GPOS2_PLANNING); ev.Report(); } else { if (bVerbose) { CEvents ev(FALSE, EVENT_NO_GPOS2); ev.Report(); } } bResult = TRUE; } else if (ulResult == LDAP_NO_SUCH_OBJECT) { DebugMsg((DM_VERBOSE, TEXT("EvalateDeferredGPOs: Objects do not exist.") )); if (dwFlags & GP_PLANMODE) { // Same error or different CEvents ev(TRUE, EVENT_NO_GPOS2_PLANNING); ev.Report(); } else { if (bVerbose) { CEvents ev(FALSE, EVENT_NO_GPOS2); ev.Report(); } } bResult = TRUE; } else if (ulResult == LDAP_SIZELIMIT_EXCEEDED) { xe = pLDAP->pfnLdapMapErrorToWin32(ulResult); DebugMsg((DM_WARNING, TEXT("EvalateDeferredGPOs: Too many GPOs in search.") )); CEvents ev(TRUE, EVENT_TOO_MANY_GPOS); ev.Report(); } else { xe = pLDAP->pfnLdapMapErrorToWin32(ulResult); DebugMsg((DM_WARNING, TEXT("EvaluteDeferredGPOs: Failed to search with error 0x%x"), ulResult)); CEvents ev(TRUE, EVENT_FAILED_GPO_SEARCH); ev.AddArgLdapError(ulResult); ev.Report(); } goto Exit; } // // If the search succeeds, but the message is empty, // store the error code and return // if ( pQuery->pMessage == NULL ) { xe = pLDAP->pfnLdapMapErrorToWin32(pQuery->pLdapHandle->ld_errno); DebugMsg((DM_WARNING, TEXT("EvaluateDeferredGPOs: Search returned an empty message structure. Error = 0x%x"), pQuery->pLdapHandle->ld_errno)); goto Exit; } if ( !MatchDnWithDeferredItems( pLDAP, pQuery, FALSE ) ) { xe = GetLastError(); goto Exit; } pQuery = pQuery->pNext; } // while if ( !EvalList( pLDAP, dwFlags, hToken, bVerbose, pDeferredForcedList, ppForcedList, ppGpContainerList, pRsopToken, pGpoFilter, pLocator ) ) { xe = GetLastError(); goto Exit; } if ( !EvalList( pLDAP, dwFlags, hToken, bVerbose, pDeferredNonForcedList, ppNonForcedList, ppGpContainerList, pRsopToken, pGpoFilter, pLocator ) ) { xe = GetLastError(); goto Exit; } bResult = TRUE; Exit: // // Free all resources except for ppForcedList, ppNonForcedList // which are owned by caller. // while ( pLdapQuery ) { pQuery = pLdapQuery->pNext; FreeLdapQuery( pLDAP, pLdapQuery ); pLdapQuery = pQuery; } return bResult; } //************************************************************* // // AddOU() // // Purpose: Appends an OU or domain to deferred list. // // Parameters: ppOUList - OU list to append to // pwszOU - OU name // gpoLink - Type of Gpo // // Return: TRUE if successful // FALSE if an error occurs // //************************************************************* BOOL AddOU( DNENTRY **ppOUList, LPTSTR pwszOU, GPO_LINK gpoLink ) { DNENTRY *pOUTemp = *ppOUList; DNENTRY *pOULast = NULL; DNENTRY *pOUNew = AllocDnEntry( pwszOU ); if ( pOUNew == NULL ) { return FALSE; } pOUNew->gpoLink = gpoLink; while ( pOUTemp ) { pOULast = pOUTemp; pOUTemp = pOUTemp->pNext; } if ( pOULast ) pOULast->pNext = pOUNew; else *ppOUList = pOUNew; return TRUE; } //************************************************************* // // EvaluateDeferredOUs() // // Purpose: Uses a single Ldap query to evaluate all OUs // // Parameters: ppOUList - OU list to append to // dwFlags - GetGPOList flags // pGPOForcedList - List of forced GPOs // pGPONonForcedList - List of non-forced GPOs // ppSOMList - List of LSDOUs // ppGpContainerList - List of Gp Containers // bVerbose - Verbose output // pld - LDAP info // pLDAP - LDAP api // pLDAPMsg - LDAP message // bBlock - Pointer to the block flag // hToken - User / machine token // // Return: TRUE if successful // FALSE if an error occurs // //************************************************************* BOOL EvaluateDeferredOUs( DNENTRY *pOUList, DWORD dwFlags, HANDLE hToken, PGROUP_POLICY_OBJECT *ppDeferredForcedList, PGROUP_POLICY_OBJECT *ppDeferredNonForcedList, LPSCOPEOFMGMT *ppSOMList, LPGPCONTAINER *ppGpContainerList, BOOL bVerbose, PLDAP pld, PLDAP_API pLDAP, BOOL *pbBlock, PRSOPTOKEN pRsopToken) { ULONG ulResult; BOOL bResult = FALSE; LDAPQUERY *pLdapQuery = NULL; BYTE berValue[8]; LDAPControl SeInfoControl = { LDAP_SERVER_SD_FLAGS_OID_W, { 5, (PCHAR)berValue }, TRUE }; PLDAPControl ServerControls[] = { &SeInfoControl, NULL }; TCHAR szGPLink[] = TEXT("gPLink"); TCHAR szGPOptions[] = TEXT("gPOptions"); TCHAR szSDProperty[] = TEXT("nTSecurityDescriptor"); LPTSTR lpAttr[] = { szGPLink, szGPOptions, szSDProperty, NULL }; DNENTRY *pOUTemp = pOUList; VOID *pData; XLastError xe; // // Setup the BER encoding for the SD // berValue[0] = 0x30; berValue[1] = 0x03; berValue[2] = 0x02; // denotes an integer berValue[3] = 0x01; // denotes size berValue[4] = (BYTE)((DACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION) & 0xF); if ( !pRsopToken ) { // // if it is not planning mode, don't get the SD // lpAttr[2] = NULL; ServerControls[0] = NULL; } if ( pOUTemp == NULL ) return TRUE; while ( pOUTemp ) { if ( !AddDN( pLDAP, &pLdapQuery, pOUTemp->pwszDN, pOUTemp, NULL ) ) { xe = GetLastError(); goto Exit; } pOUTemp = pOUTemp->pNext; } pLdapQuery->pLdapHandle = pld; // // Turn referrals off because this is a single domain call // if ( !pRsopToken ) { pData = (VOID *) LDAP_OPT_OFF; ulResult = pLDAP->pfnldap_set_option( pLdapQuery->pLdapHandle, LDAP_OPT_REFERRALS, &pData ); if ( ulResult != LDAP_SUCCESS ) { xe = pLDAP->pfnLdapMapErrorToWin32(ulResult); DebugMsg((DM_WARNING, TEXT("EvaluteDeferredOUs: Failed to turn off referrals with error %d"), ulResult)); goto Exit; } } ulResult = pLDAP->pfnldap_search_ext_s(pld, pLdapQuery->pwszDomain, LDAP_SCOPE_SUBTREE, pLdapQuery->pwszFilter, lpAttr, FALSE, (PLDAPControl*)ServerControls, NULL, NULL, 0, &pLdapQuery->pMessage); // // If the search fails, store the error code and return // if (ulResult != LDAP_SUCCESS) { if (ulResult == LDAP_NO_SUCH_ATTRIBUTE) { DebugMsg((DM_VERBOSE, TEXT("EvaluateDeferredOUs: All objects can not be accessed."))); bResult = TRUE; } else if (ulResult == LDAP_NO_SUCH_OBJECT) { DebugMsg((DM_VERBOSE, TEXT("EvalateDeferredOUs: Objects do not exist.") )); bResult = TRUE; } else if (ulResult == LDAP_SIZELIMIT_EXCEEDED) { xe = pLDAP->pfnLdapMapErrorToWin32(ulResult); DebugMsg((DM_WARNING, TEXT("EvalateDeferredOUs: Too many linked GPOs in search.") )); CEvents ev(TRUE, EVENT_TOO_MANY_GPOS); ev.Report(); } else { xe = pLDAP->pfnLdapMapErrorToWin32(ulResult); DebugMsg((DM_WARNING, TEXT("EvaluateDeferredOUs: Failed to search with error %d"), ulResult)); CEvents ev(TRUE, EVENT_FAILED_OU_SEARCH); ev.AddArg(ulResult); ev.Report(); } goto Exit; } // // If the search succeeds, but the message is empty, // store the error code and return // if ( pLdapQuery->pMessage == NULL ) { xe = pLDAP->pfnLdapMapErrorToWin32(pld->ld_errno); DebugMsg((DM_WARNING, TEXT("EvaluateDeferredOUs: Search returned an empty message structure. Error = %d"), pld->ld_errno)); goto Exit; } if ( !MatchDnWithDeferredItems( pLDAP, pLdapQuery, TRUE ) ) { xe = GetLastError(); goto Exit; } // // Evaluate the OU list // pOUTemp = pOUList; while ( pOUTemp ) { PLDAPMessage pOUMsg = pOUTemp->pOUMsg; if ( pOUMsg == NULL ) { xe = ERROR_INVALID_DATA; DebugMsg((DM_WARNING, TEXT("EvaluateDeferredOUs: Object <%s> cannot be accessed"), pOUTemp->pwszDN )); CEvents ev(TRUE, EVENT_OU_NOTFOUND); ev.AddArg(pOUTemp->pwszDN); ev.Report(); goto Exit; } else { if ( !SearchDSObject( pOUTemp->pwszDN, dwFlags, hToken, ppDeferredForcedList, ppDeferredNonForcedList, ppSOMList, ppGpContainerList, bVerbose, pOUTemp->gpoLink, pld, pLDAP, pOUMsg, pbBlock, pRsopToken)) { xe = GetLastError(); DebugMsg((DM_WARNING, TEXT("EvaluateDeferredOUs: SearchDSObject failed") )); goto Exit; } } pOUTemp = pOUTemp->pNext; } bResult = TRUE; Exit: while ( pLdapQuery ) { LDAPQUERY *pQuery = pLdapQuery->pNext; FreeLdapQuery( pLDAP, pLdapQuery ); pLdapQuery = pQuery; } return bResult; } //************************************************************* // // GetMachineDomainDS() // // Purpose: Obtain the machine domain DS // // Parameters: pNetApi32 - netapi32.dll // pLdapApi - wldap32.dll // // Return: valid PLDAP if successful // 0 if an error occurs // //************************************************************* PLDAP GetMachineDomainDS( PNETAPI32_API pNetApi32, PLDAP_API pLdapApi ) { PLDAP pld = 0; DWORD dwResult = 0; PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pDsInfo = NULL; ULONG ulResult; VOID *pData; XLastError xe; // // get the machine domain name // dwResult = pNetApi32->pfnDsRoleGetPrimaryDomainInformation( NULL, DsRolePrimaryDomainInfoBasic, (PBYTE *)&pDsInfo ); if ( dwResult == ERROR_SUCCESS ) { SEC_WINNT_AUTH_IDENTITY_EXW secIdentity; pld = pLdapApi->pfnldap_init( pDsInfo->DomainNameDns, LDAP_PORT ); if (!pld) { xe = pLdapApi->pfnLdapMapErrorToWin32(pLdapApi->pfnLdapGetLastError()); DebugMsg((DM_WARNING, TEXT("GetMachineDomainDS: ldap_open for <%s> failed with = 0x%x or %d"), pDsInfo->DomainNameDns, pLdapApi->pfnLdapGetLastError(), GetLastError())); return pld; } // // Turn on Packet integrity flag // pData = (VOID *) LDAP_OPT_ON; ulResult = pLdapApi->pfnldap_set_option(pld, LDAP_OPT_SIGN, &pData); if (ulResult != LDAP_SUCCESS) { xe = pLdapApi->pfnLdapMapErrorToWin32(ulResult); DebugMsg((DM_WARNING, TEXT("GetMachineDomainDS: Failed to turn on LDAP_OPT_SIGN with %d"), ulResult)); pLdapApi->pfnldap_unbind(pld); pld = 0; return pld; } ulResult = pLdapApi->pfnldap_connect(pld, 0); if (ulResult != LDAP_SUCCESS) { xe = pLdapApi->pfnLdapMapErrorToWin32(ulResult); DebugMsg((DM_WARNING, TEXT("GetMachineDomainDS: Failed to connect with %d"), ulResult)); pLdapApi->pfnldap_unbind(pld); pld = 0; return pld; } // // For machine policies specifically ask for Kerberos as the only authentication // mechanism. Otherwise if Kerberos were to fail for some reason, then NTLM is used // and localsystem context has no real credentials, which means that we won't get // any GPOs back. // secIdentity.Version = SEC_WINNT_AUTH_IDENTITY_VERSION; secIdentity.Length = sizeof(SEC_WINNT_AUTH_IDENTITY_EXW); secIdentity.User = 0; secIdentity.UserLength = 0; secIdentity.Domain = 0; secIdentity.DomainLength = 0; secIdentity.Password = 0; secIdentity.PasswordLength = 0; secIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; secIdentity.PackageList = wszKerberos; secIdentity.PackageListLength = lstrlen( wszKerberos ); if ( (ulResult = pLdapApi->pfnldap_bind_s (pld, 0, (WCHAR *)&secIdentity, LDAP_AUTH_SSPI)) != LDAP_SUCCESS ) { DebugMsg((DM_WARNING, TEXT("GetMachineDomainDS: ldap_bind_s failed with %d"), ulResult)); xe = pLdapApi->pfnLdapMapErrorToWin32(ulResult); pLdapApi->pfnldap_unbind(pld); pld = 0; } pNetApi32->pfnDsRoleFreeMemory( pDsInfo ); } else { xe = dwResult; DebugMsg((DM_WARNING, TEXT("GetMachineDomainDS: The domain does not have a DS"))); } return pld; } //************************************************************* // // AllocSOM() // // Purpose: Allocates a new struct for SOM // // // Parameters: pwszSOMId - Name of SOM // // Return: Pointer if successful // NULL if an error occurs // //************************************************************* SCOPEOFMGMT *AllocSOM( LPWSTR pwszSOMId ) { XLastError xe; HRESULT hr = S_OK; SCOPEOFMGMT *pSOM = (SCOPEOFMGMT *) LocalAlloc( LPTR, sizeof(SCOPEOFMGMT) ); if ( pSOM == NULL ) { xe = GetLastError(); return NULL; } pSOM->pwszSOMId = (LPWSTR) LocalAlloc( LPTR, (lstrlen(pwszSOMId) + 1) * sizeof(WCHAR) ); if ( pSOM->pwszSOMId == NULL ) { xe = GetLastError(); LocalFree( pSOM ); return NULL; } hr = StringCchCopy( pSOM->pwszSOMId, lstrlen(pwszSOMId) + 1, pwszSOMId ); ASSERT(SUCCEEDED(hr)); return pSOM; } //************************************************************* // // FreeSOM() // // Purpose: Frees SOM struct // // Parameters: pSOM - SOM to free // //************************************************************* void FreeSOM( SCOPEOFMGMT *pSOM ) { GPLINK *pGpLink = NULL; if ( pSOM ) { LocalFree( pSOM->pwszSOMId ); pGpLink = pSOM->pGpLinkList; while ( pGpLink ) { GPLINK *pTemp = pGpLink->pNext; FreeGpLink( pGpLink ); pGpLink = pTemp; } LocalFree( pSOM ); } } //************************************************************* // // AllocGpLink() // // Purpose: Allocates a new struct for GpLink // // // Parameters: pwszGPO - Name of GPO // // Return: Pointer if successful // NULL if an error occurs // //************************************************************* GPLINK *AllocGpLink( LPWSTR pwszGPO, DWORD dwOptions ) { // // Strip out "LDAP://" prefix to get canonical Gpo path // WCHAR wszPrefix[] = TEXT("LDAP://"); INT iPrefixLen = lstrlen( wszPrefix ); WCHAR *pwszPath = pwszGPO; GPLINK *pGpLink = NULL; XLastError xe; HRESULT hr = S_OK; if ( (lstrlen(pwszGPO) > iPrefixLen) && CompareString( LOCALE_INVARIANT, NORM_IGNORECASE, pwszGPO, iPrefixLen, wszPrefix, iPrefixLen ) == CSTR_EQUAL ) { pwszPath = pwszGPO + iPrefixLen; } pGpLink = (GPLINK *) LocalAlloc( LPTR, sizeof(GPLINK) ); if ( pGpLink == NULL ) { xe = GetLastError(); return NULL; } pGpLink->pwszGPO = (LPWSTR) LocalAlloc( LPTR, (lstrlen(pwszPath) + 1) * sizeof(WCHAR) ); if ( pGpLink->pwszGPO == NULL ) { xe = GetLastError(); LocalFree( pGpLink ); return NULL; } hr = StringCchCopy( pGpLink->pwszGPO, lstrlen(pwszPath) + 1, pwszPath ); ASSERT(SUCCEEDED(hr)); pGpLink->bEnabled = (dwOptions & GPO_FLAG_DISABLE) ? FALSE : TRUE; if ( dwOptions & GPO_FLAG_FORCE ) pGpLink->bNoOverride = TRUE; return pGpLink; } //************************************************************* // // FreeGpLink() // // Purpose: Frees GpLink struct // // Parameters: pGpLink - GpLink to free // //************************************************************* void FreeGpLink( GPLINK *pGpLink ) { if ( pGpLink ) { LocalFree( pGpLink->pwszGPO ); LocalFree( pGpLink ); } } //************************************************************* // // AllocGpContainer() // // Purpose: Allocates a new struct for GpContainer // // // Parameters: dwFlags - Flags // bFound - Was Gpo found ? // bAccessGranted - Was access granted ? // bDisabled - Is Gp Container disabled ? // dwVersion - Version # // lpDSPath - DS path to Gpo // lpFileSysPath - Sysvol path to Gpo // lpDisplayName - Friendly name // lpGpoName - Guid name // pSD - Security descriptor // cbSDLen - Length of security descriptor // bFilterAllowed - Does GPO pass filter check // pwszFilterId - WQL filter id // // Return: Pointer if successful // NULL if an error occurs // //************************************************************* GPCONTAINER *AllocGpContainer( DWORD dwFlags, BOOL bFound, BOOL bAccessGranted, BOOL bDisabled, DWORD dwVersion, LPTSTR lpDSPath, LPTSTR lpFileSysPath, LPTSTR lpDisplayName, LPTSTR lpGpoName, PSECURITY_DESCRIPTOR pSD, DWORD cbSDLen, BOOL bFilterAllowed, WCHAR *pwszFilterId, LPWSTR szSOM, DWORD dwOptions ) { WCHAR wszMachPrefix[] = TEXT("LDAP://CN=Machine,"); INT iMachPrefixLen = lstrlen( wszMachPrefix ); WCHAR wszUserPrefix[] = TEXT("LDAP://CN=User,"); INT iUserPrefixLen = lstrlen( wszUserPrefix ); WCHAR *pwszPath = lpDSPath; BOOL bResult = FALSE; GPCONTAINER *pGpContainer = NULL; XLastError xe; HRESULT hr = S_OK; // // Strip out prefix, if any, to get the canonical path to Gpo // if ( (lstrlen(lpDSPath) > iUserPrefixLen) && CompareString( LOCALE_INVARIANT, NORM_IGNORECASE, lpDSPath, iUserPrefixLen, wszUserPrefix, iUserPrefixLen ) == CSTR_EQUAL ) { pwszPath = lpDSPath + iUserPrefixLen; } else if ( (lstrlen(lpDSPath) > iMachPrefixLen) && CompareString( LOCALE_INVARIANT, NORM_IGNORECASE, lpDSPath, iMachPrefixLen, wszMachPrefix, iMachPrefixLen ) == CSTR_EQUAL ) { pwszPath = lpDSPath + iMachPrefixLen; } pGpContainer = (GPCONTAINER *) LocalAlloc( LPTR, sizeof(GPCONTAINER) ); if ( pGpContainer == NULL ) { xe = GetLastError(); DebugMsg((DM_WARNING, TEXT("AllocGpContainer: Unable to allocate memory for GpContainer object"))); return NULL; } pGpContainer->bAccessDenied = !bAccessGranted; pGpContainer->bFound = bFound; if ( dwFlags & GP_MACHINE ) { pGpContainer->bMachDisabled = bDisabled; pGpContainer->dwMachVersion = dwVersion; } else { pGpContainer->bUserDisabled = bDisabled; pGpContainer->dwUserVersion = dwVersion; } if ( pwszPath ) { pGpContainer->pwszDSPath = (LPWSTR) LocalAlloc( LPTR, (lstrlen(pwszPath) + 1) * sizeof(WCHAR) ); if ( pGpContainer->pwszDSPath == NULL ) { xe = GetLastError(); DebugMsg((DM_WARNING, TEXT("AllocGpContainer: Unable to allocate memory for GpContainer object"))); goto Exit; } hr = StringCchCopy( pGpContainer->pwszDSPath, lstrlen(pwszPath) + 1, pwszPath ); ASSERT(SUCCEEDED(hr)); } if ( lpGpoName ) { pGpContainer->pwszGPOName = (LPWSTR) LocalAlloc( LPTR, (lstrlen(lpGpoName) + 1) * sizeof(WCHAR) ); if ( pGpContainer->pwszGPOName == NULL ) { xe = GetLastError(); DebugMsg((DM_WARNING, TEXT("AllocGpContainer: Unable to allocate memory for GpContainer object"))); goto Exit; } hr = StringCchCopy( pGpContainer->pwszGPOName, lstrlen(lpGpoName) + 1, lpGpoName ); ASSERT(SUCCEEDED(hr)); } if ( lpDisplayName ) { pGpContainer->pwszDisplayName = (LPWSTR) LocalAlloc( LPTR, (lstrlen(lpDisplayName) + 1) * sizeof(WCHAR) ); if ( pGpContainer->pwszDisplayName == NULL ) { xe = GetLastError(); DebugMsg((DM_WARNING, TEXT("AllocGpContainer: Unable to allocate memory for GpContainer object"))); goto Exit; } hr = StringCchCopy( pGpContainer->pwszDisplayName, lstrlen(lpDisplayName) + 1, lpDisplayName ); ASSERT(SUCCEEDED(hr)); } if ( lpFileSysPath ) { pGpContainer->pwszFileSysPath = (LPWSTR) LocalAlloc( LPTR, (lstrlen(lpFileSysPath) + 1) * sizeof(WCHAR) ); if ( pGpContainer->pwszFileSysPath == NULL ) { xe = GetLastError(); DebugMsg((DM_WARNING, TEXT("AllocGpContainer: Unable to allocate memory for GpContainer object"))); goto Exit; } hr = StringCchCopy( pGpContainer->pwszFileSysPath, lstrlen(lpFileSysPath) + 1, lpFileSysPath ); ASSERT(SUCCEEDED(hr)); } if ( cbSDLen != 0 ) { pGpContainer->pSD = (PSECURITY_DESCRIPTOR) LocalAlloc( LPTR, cbSDLen ); if ( pGpContainer->pSD == NULL ) { xe = GetLastError(); DebugMsg((DM_WARNING, TEXT("AllocGpContainer: Unable to allocate memory for GpContainer object"))); goto Exit; } CopyMemory( pGpContainer->pSD, pSD, cbSDLen ); } pGpContainer->cbSDLen = cbSDLen; pGpContainer->bFilterAllowed = bFilterAllowed; if ( pwszFilterId ) { pGpContainer->pwszFilterId = (LPWSTR) LocalAlloc( LPTR, (lstrlen(pwszFilterId) + 1) * sizeof(WCHAR) ); if ( pGpContainer->pwszFilterId == NULL ) { xe = GetLastError(); DebugMsg((DM_WARNING, TEXT("AllocGpContainer: Unable to allocate memory for GpContainer object"))); goto Exit; } hr = StringCchCopy( pGpContainer->pwszFilterId, lstrlen(pwszFilterId) + 1, pwszFilterId ); ASSERT(SUCCEEDED(hr)); } if ( szSOM ) { pGpContainer->szSOM = (LPWSTR) LocalAlloc( LPTR, (lstrlen(szSOM) + 1) * sizeof(WCHAR) ); if ( !pGpContainer->szSOM ) { xe = GetLastError(); DebugMsg((DM_WARNING, TEXT("AllocGpContainer: Unable to allocate memory for GpContainer object"))); goto Exit; } hr = StringCchCopy( pGpContainer->szSOM, lstrlen(szSOM) + 1, szSOM ); ASSERT(SUCCEEDED(hr)); } pGpContainer->dwOptions = dwOptions; bResult = TRUE; Exit: if ( !bResult ) { LocalFree( pGpContainer->pwszDSPath ); LocalFree( pGpContainer->pwszGPOName ); LocalFree( pGpContainer->pwszDisplayName ); LocalFree( pGpContainer->pwszFileSysPath ); LocalFree( pGpContainer->pSD ); LocalFree( pGpContainer->pwszFilterId ); LocalFree( pGpContainer->szSOM ); LocalFree( pGpContainer ); return 0; } return pGpContainer; } //************************************************************* // // FreeGpContainer() // // Purpose: Frees GpContainer struct // // Parameters: pGpContainer - Gp Container to free // //************************************************************* void FreeGpContainer( GPCONTAINER *pGpContainer ) { if ( pGpContainer ) { LocalFree( pGpContainer->pwszDSPath ); LocalFree( pGpContainer->pwszGPOName ); LocalFree( pGpContainer->pwszDisplayName ); LocalFree( pGpContainer->pwszFileSysPath ); LocalFree( pGpContainer->pSD ); LocalFree( pGpContainer->pwszFilterId ); LocalFree( pGpContainer->szSOM ); LocalFree( pGpContainer ); } } //************************************************************* // // FreeSOMList() // // Purpose: Frees list of SOMs // // Parameters: pSOMList - SOM list to free // //************************************************************* void FreeSOMList( SCOPEOFMGMT *pSOMList ) { if ( pSOMList == NULL ) return; while ( pSOMList ) { SCOPEOFMGMT *pTemp = pSOMList->pNext; FreeSOM( pSOMList ); pSOMList = pTemp; } } //************************************************************* // // FreeGpContainerList() // // Purpose: Frees list of Gp Containers // // Parameters: pGpContainerList - Gp Container list to free // //************************************************************* void FreeGpContainerList( GPCONTAINER *pGpContainerList ) { if ( pGpContainerList == NULL ) return; while ( pGpContainerList ) { GPCONTAINER *pTemp = pGpContainerList->pNext; FreeGpContainer( pGpContainerList ); pGpContainerList = pTemp; } } LPTSTR GetSomPath( LPTSTR szContainer ) { while (*szContainer) { // // See if the DN name starts with OU= // if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE, szContainer, 3, TEXT("OU="), 3) == CSTR_EQUAL) { break; } // // See if the DN name starts with DC= // else if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE, szContainer, 3, TEXT("DC="), 3) == CSTR_EQUAL) { break; } // // Move to the next chunk of the DN name // while (*szContainer && (*szContainer != TEXT(','))) { szContainer++; } if (*szContainer == TEXT(',')) { szContainer++; } } if (!*szContainer) { return NULL; } return szContainer; }