Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3567 lines
113 KiB

//*************************************************************
//
// 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;
}