|
|
//*************************************************************
//
// Group Policy Support - Queries about the Policies
//
// Microsoft Confidential
// Copyright (c) Microsoft Corporation 1997-1998
// All rights reserved
//
//*************************************************************
#include "gphdr.h"
#include <strsafe.h>
//*************************************************************
//
// 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<WCHAR> 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; }
|