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.
 
 
 
 
 
 

1342 lines
42 KiB

//*************************************************************
//
// Group Policy Support - Getting the list of gpos
//
// Microsoft Confidential
// Copyright (c) Microsoft Corporation 1997-1998
// All rights reserved
//
//*************************************************************
#include "gphdr.h"
#include <strsafe.h>
//*************************************************************
//
// DsQuoteSearchFilter()
//
//
// Comment: This function takes a DN and returns a version
// of the DN escaped according to RFC's 2253 and 2254
//
// Return: A pointer to the quoted string, which must be
// freed by the caller. If the function fails, the
// return value is 0.
//
//*************************************************************
LPWSTR
DsQuoteSearchFilter( LPCWSTR szUDN )
{
DmAssert(NULL != szUDN );
if (NULL == szUDN)
return NULL;
DWORD cUDN = wcslen( szUDN );
LPWSTR szQDN = 0, szTemp = 0;;
HRESULT hr = S_OK;
//
// Note that the maximum length of the quoted string would result
// if every single character in the DN needed to be escaped. Since
// the escaped characters are of the form '\nn', the escaped string
// could be at most 3 times the size of the original string
//
if ( cUDN )
{
szTemp = szQDN = (LPWSTR) LocalAlloc( LPTR, ( cUDN * 3 + 1 ) * sizeof( WCHAR ) );
}
if ( !szQDN )
{
return 0;
}
while ( *szUDN )
{
WCHAR szBuffer[16];
if ( *szUDN == L'*' || *szUDN == L'(' || *szUDN == L')' || !*szUDN )
{
//
// convert special characters to \NN
//
*szQDN++ = L'\\';
DWORD dwQDNLength = cUDN * 3 + 1 - (DWORD) (szQDN - szTemp);
hr = StringCchCat( szQDN, dwQDNLength, _itow( *szUDN++, szBuffer, 16 ) );
ASSERT(SUCCEEDED(hr));
szQDN += 2;
}
else
{
*szQDN++ = *szUDN++;
}
}
*szQDN = 0;
return szTemp;
}
//*************************************************************
//
// GetGPOInfo()
//
// Purpose: Gets the GPO info for this threads token.
//
// Parameters: dwFlags - GPO_LIST_FLAG_* from userenv.h
// lpHostName - Domain DN name or DC server name
// lpDNName - User or Machine DN name
// lpComputerName - Computer name used for site look up
// lpGPOList - Receives the list of GROUP_POLICY_OBJECTs
// ppSOMList - List of LSDOUs returned here
// ppGpContainerList - List of Gp containers returned here
// pNetAPI32 - Netapi32 function table
// bMachineTokenOK - Ok to query for the machine token
// pRsopToken - Rsop security token
// pGpoFilter - Gpo filter
// pLocator - WMI interfaces
//
// Comment: This is a link list of GROUP_POLICY_OBJECTs. Each can be
// free'ed with LocalFree() or calling FreeGPOList()
//
// The processing sequence is:
//
// Local Forest Site Domain OrganizationalUnit
//
// Note that we process this list backwards to get the
// correct sequencing for the force flag.
//
// Return: TRUE if successful
// FALSE if an error occurs
//
//*************************************************************
BOOL GetGPOInfo(DWORD dwFlags,
LPTSTR lpHostName,
LPTSTR lpDNName,
LPCTSTR lpComputerName,
PGROUP_POLICY_OBJECT *lpGPOList,
LPSCOPEOFMGMT *ppSOMList,
LPGPCONTAINER *ppGpContainerList,
PNETAPI32_API pNetAPI32,
BOOL bMachineTokenOk,
PRSOPTOKEN pRsopToken,
LPWSTR pwszSiteName,
CGpoFilter *pGpoFilter,
CLocator *pLocator )
{
PGROUP_POLICY_OBJECT pGPOForcedList = NULL, pGPONonForcedList = NULL;
PLDAP pld = NULL;
ULONG ulResult;
BOOL bResult = FALSE;
BOOL bBlock = FALSE;
LPTSTR lpDSObject, lpTemp;
PLDAPMessage pLDAPMsg = NULL;
TCHAR szGPOPath[MAX_PATH];
TCHAR szGPOName[50];
BOOL bVerbose;
DWORD dwVersion, dwOptions;
TCHAR szNamingContext[] = TEXT("configurationNamingContext");
TCHAR szSDProperty[] = TEXT("nTSecurityDescriptor"); // this is unused currently
LPTSTR lpAttr[] = { szNamingContext,
szSDProperty,
0 };
PGROUP_POLICY_OBJECT lpGPO, lpGPOTemp;
WIN32_FILE_ATTRIBUTE_DATA fad;
PLDAP_API pldap_api;
HANDLE hToken = NULL, hTempToken;
DWORD dwFunctionalityVersion;
PGROUP_POLICY_OBJECT pDeferredForcedList = NULL, pDeferredNonForcedList = NULL;
DNENTRY *pDeferredOUList = NULL; // List of deferred OUs
TCHAR* szDN;
PSECUR32_API pSecur32Api;
BOOL bAddedOU = FALSE;
PLDAP pldMachine = 0;
VOID *pData;
BOOL bOwnSiteName = FALSE;
BOOL bRsopLogging = (ppSOMList != 0);
BOOL bRsopPlanningMode = (pRsopToken != 0);
XLastError xe;
HRESULT hr = S_OK;
//
// Verbose output
//
DebugMsg((DM_VERBOSE, TEXT("GetGPOInfo: ********************************")));
DebugMsg((DM_VERBOSE, TEXT("GetGPOInfo: Entering...")));
//
// Start with lpGPOList being a pointer to null
//
*lpGPOList = NULL;
DmAssert( *ppSOMList == NULL );
DmAssert( *ppGpContainerList == NULL );
//
// Check if we should be verbose to the event log
//
bVerbose = CheckForVerbosePolicy();
//
// Load the secur32 api
//
pSecur32Api = LoadSecur32();
if (!pSecur32Api) {
xe = GetLastError();
DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to load secur32 api.")));
goto Exit;
}
//
// Load the ldap api
//
pldap_api = LoadLDAP();
if (!pldap_api) {
xe = GetLastError();
DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to load ldap api.")));
goto Exit;
}
//=========================================================================
//
// If we don't have a DS server or user / machine name, we can
// skip the DS stuff and only check for a local GPO
//
//=========================================================================
if (!lpHostName || !lpDNName) {
DebugMsg((DM_VERBOSE, TEXT("GetGPOInfo: lpHostName or lpDNName is NULL. Skipping DS stuff.")));
goto CheckLocal;
}
//
// Get the user or machine's token
//
if (bMachineTokenOk && (dwFlags & GPO_LIST_FLAG_MACHINE)) {
hToken = GetMachineToken();
if (!hToken) {
xe = GetLastError();
DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to get the machine token with %d"),
GetLastError()));
CEvents ev(TRUE, EVENT_FAILED_MACHINE_TOKEN);
ev.AddArgWin32Error(xe); ev.Report();
goto Exit;
}
} else {
if (!OpenThreadToken (GetCurrentThread(), TOKEN_IMPERSONATE | TOKEN_READ | TOKEN_DUPLICATE,
TRUE, &hTempToken)) {
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_IMPERSONATE | TOKEN_READ | TOKEN_DUPLICATE,
&hTempToken)) {
xe = GetLastError();
DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to get a token with %d"),
GetLastError()));
goto Exit;
}
}
//
// Duplicate it so it can be used for impersonation
//
if (!DuplicateTokenEx(hTempToken, TOKEN_QUERY, // Fixing bug 568191.
NULL, SecurityImpersonation, TokenImpersonation,
&hToken))
{
xe = GetLastError();
DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to duplicate the token with %d"),
GetLastError()));
CloseHandle (hTempToken);
goto Exit;
}
CloseHandle (hTempToken);
}
//
// Get a connection to the DS
//
if ((lpHostName[0] == TEXT('\\')) && (lpHostName[1] == TEXT('\\'))) {
lpHostName = lpHostName + 2;
}
pld = pldap_api->pfnldap_init( lpHostName, LDAP_PORT);
if (!pld) {
xe = GetLastError();
DebugMsg((DM_WARNING, TEXT("GetGPOInfo: ldap_open for <%s> failed with = 0x%x or %d"),
lpHostName, pldap_api->pfnLdapGetLastError(), GetLastError()));
CEvents ev(TRUE, EVENT_FAILED_DS_CONNECT);
ev.AddArg(lpHostName); ev.AddArgLdapError(pldap_api->pfnLdapGetLastError()); ev.Report();
goto Exit;
}
DebugMsg((DM_VERBOSE, TEXT("GetGPOInfo: Server connection established.")));
//
// Turn on Packet integrity flag
//
pData = (VOID *) LDAP_OPT_ON;
ulResult = pldap_api->pfnldap_set_option(pld, LDAP_OPT_SIGN, &pData);
if (ulResult != LDAP_SUCCESS) {
xe = pldap_api->pfnLdapMapErrorToWin32(ulResult);
DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to turn on LDAP_OPT_SIGN with %d"), ulResult));
goto Exit;
}
ulResult = pldap_api->pfnldap_connect(pld, 0);
if (ulResult != LDAP_SUCCESS) {
xe = pldap_api->pfnLdapMapErrorToWin32(ulResult);
DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to connect %s with %d"), lpHostName, ulResult));
pldap_api->pfnldap_unbind(pld);
pld = 0;
goto Exit;
}
//
// Bind to the DS.
//
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_api->pfnldap_bind_s (pld, NULL, (WCHAR *)&secIdentity, LDAP_AUTH_SSPI);
} else
ulResult = pldap_api->pfnldap_bind_s (pld, NULL, NULL, LDAP_AUTH_SSPI);
if (ulResult != LDAP_SUCCESS) {
xe = pldap_api->pfnLdapMapErrorToWin32(ulResult);
DebugMsg((DM_WARNING, TEXT("GetGPOInfo: ldap_bind_s failed with = <%d>"),
ulResult));
CEvents ev(TRUE, EVENT_FAILED_DS_BIND);
ev.AddArg(lpHostName); ev.AddArgLdapError(ulResult); ev.Report();
goto Exit;
}
DebugMsg((DM_VERBOSE, TEXT("GetGPOInfo: Bound successfully.")));
//=========================================================================
//
// Check the organizational units and domain for policy
//
//=========================================================================
if (!(dwFlags & GPO_LIST_FLAG_SITEONLY)) {
//
// Loop through the DN Name to find each OU or the domain
//
lpDSObject = lpDNName;
while (*lpDSObject) {
//
// See if the DN name starts with OU=
//
if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE,
lpDSObject, 3, TEXT("OU="), 3) == CSTR_EQUAL) {
if ( !AddOU( &pDeferredOUList, lpDSObject, GPLinkOrganizationalUnit ) ) {
xe = GetLastError();
goto Exit;
}
}
//
// See if the DN name starts with DC=
//
else if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE,
lpDSObject, 3, TEXT("DC="), 3) == CSTR_EQUAL) {
if ( !AddOU( &pDeferredOUList, lpDSObject, GPLinkDomain ) ) {
xe = GetLastError();
goto Exit;
}
//
// Now that we've found a DN name that starts with DC=
// we exit the loop now.
//
break;
}
//
// Move to the next chunk of the DN name
//
while (*lpDSObject && (*lpDSObject != TEXT(','))) {
lpDSObject++;
}
if (*lpDSObject == TEXT(',')) {
lpDSObject++;
}
}
//
// Evaluate deferred OUs with single Ldap query
//
if ( !EvaluateDeferredOUs( pDeferredOUList,
dwFlags,
hToken,
&pDeferredForcedList,
&pDeferredNonForcedList,
ppSOMList,
ppGpContainerList,
bVerbose,
pld,
pldap_api,
&bBlock,
pRsopToken ) )
{
xe = GetLastError();
DebugMsg((DM_WARNING, TEXT("GetGPOInfo: EvaluateDeferredOUs failed. Exiting") ));
goto Exit;
}
}
//=========================================================================
//
// Check the site object for policy
//
//=========================================================================
//
// Now we need to query for the domain name.
//
//
// Now we need to query for the domain name. This is done by
// reading the operational attribute configurationNamingContext
//
if (pwszSiteName) {
pldMachine = GetMachineDomainDS( pNetAPI32, pldap_api );
if ( pldMachine )
{
pLDAPMsg = 0;
ulResult = pldap_api->pfnldap_search_s( pldMachine,
TEXT(""),
LDAP_SCOPE_BASE,
TEXT("(objectClass=*)"),
lpAttr,
FALSE,
&pLDAPMsg);
if ( ulResult == LDAP_SUCCESS )
{
LPTSTR* pszValues = pldap_api->pfnldap_get_values( pldMachine, pLDAPMsg, szNamingContext );
if ( pszValues )
{
LPWSTR szSite;
WCHAR szSiteFmt[] = TEXT("CN=%s,CN=Sites,%s");
//
// Combine the domain name + site name to get the full
// DS object path
//
DWORD dwSiteLen = lstrlen(pwszSiteName) + lstrlen(*pszValues) + lstrlen(szSiteFmt) + 1;
szSite = (LPWSTR) LocalAlloc( LPTR, (dwSiteLen) * sizeof(WCHAR));
if (szSite)
{
(void) StringCchPrintf( szSite, dwSiteLen, szSiteFmt, pwszSiteName, *pszValues );
if (SearchDSObject (szSite, dwFlags, hToken, &pDeferredForcedList, &pDeferredNonForcedList,
ppSOMList, ppGpContainerList,
bVerbose, GPLinkSite, pldMachine,
pldap_api, NULL, &bBlock, pRsopToken )) {
bAddedOU = TRUE;
} else {
xe = GetLastError();
DebugMsg((DM_WARNING, TEXT("GetGPOInfo: SearchDSObject failed. Exiting.")));
}
LocalFree(szSite);
}
else
{
xe = ERROR_OUTOFMEMORY;
}
pldap_api->pfnldap_value_free( pszValues );
}
else
{
xe = GetLastError();
DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to get values.")));
}
pldap_api->pfnldap_msgfree( pLDAPMsg );
}
else
{
xe = pldap_api->pfnLdapMapErrorToWin32(ulResult);
DebugMsg((DM_WARNING, TEXT("GetGPOInfo: ldap_search_s failed with = <%d>"), ulResult) );
CEvents ev(TRUE, EVENT_FAILED_ROOT_SEARCH);
ev.AddArgLdapError(ulResult); ev.Report();
}
}
if ( !bAddedOU )
{
goto Exit;
}
}
#ifdef FGPO_SUPPORTED
//=========================================================================
//
// Now query for the forest GPO
//
//=========================================================================
pLDAPMsg = 0;
ulResult = pldap_api->pfnldap_search_s( pld,
TEXT(""),
LDAP_SCOPE_BASE,
TEXT("(objectClass=*)"),
lpAttr,
FALSE,
&pLDAPMsg);
if ( ulResult == LDAP_SUCCESS )
{
LPTSTR* pszValues = pldap_api->pfnldap_get_values( pld, pLDAPMsg, szNamingContext );
if (pszValues) {
if (SearchDSObject (*pszValues, dwFlags, hToken, &pDeferredForcedList, &pDeferredNonForcedList,
ppSOMList, ppGpContainerList,
bVerbose, GPLinkForest, pld,
pldap_api, NULL, &bBlock, pRsopToken )) {
bAddedOU = TRUE;
}
else {
xe = GetLastError();
DebugMsg((DM_WARNING, TEXT("GetGPOInfo: SearchDSObject failed for forest GPOs. Exiting.")));
}
pldap_api->pfnldap_value_free( pszValues );
}
else
{
xe = GetLastError();
DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to get values for user config container.")));
}
pldap_api->pfnldap_msgfree( pLDAPMsg );
}
else
{
xe = pldap_api->pfnLdapMapErrorToWin32(ulResult);
DebugMsg((DM_WARNING, TEXT("GetGPOInfo: ldap_search_s failed with = <%d>"), ulResult) );
CEvents ev(TRUE, EVENT_FAILED_ROOT_SEARCH);
ev.AddArgLdapError(ulResult); ev.Report();
}
if ( !bAddedOU )
{
goto Exit;
}
#endif
CheckLocal:
//
// Evaluate all GPOs deferred so far with single Ldap query
//
if ( !EvaluateDeferredGPOs( pld,
pldap_api,
lpHostName,
dwFlags,
hToken,
bVerbose,
pDeferredForcedList,
pDeferredNonForcedList,
&pGPOForcedList,
&pGPONonForcedList,
ppGpContainerList,
pRsopToken,
pGpoFilter, pLocator ) )
{
xe = GetLastError();
DebugMsg((DM_WARNING, TEXT("GetGPOInfo: EvaluateDeferredGPOs failed. Exiting") ));
goto Exit;
}
//=========================================================================
//
// Check if we have a local GPO. If so, add it to the list. In planning mode
// local Gpo processing is omitted because planning mode is generated on a DC
// and local Gpo should refer to Gpo on the target computer.
//
//=========================================================================
if (!bRsopPlanningMode && !(dwFlags & GPO_LIST_FLAG_SITEONLY)) {
BOOL bDisabled = FALSE;
BOOL bOldGpoVersion = FALSE;
BOOL bNoGpoData = FALSE;
DWORD dwSize = MAX_PATH;
DWORD dwCount = 0;
BOOL bOk = FALSE;
TCHAR *pszExtensions = 0;
BOOL bGptIniExists = FALSE;
DWORD dwRet;
//
// If the gpt.ini doesn't exist because this is a clean installed machine,
// we manufacture default state for it here -- these values must be
// initialized since they normally require the gpt.ini
//
dwFunctionalityVersion = 2;
dwOptions = 0;
bDisabled = FALSE;
dwVersion = 0;
bNoGpoData = TRUE;
//
// Retrieve the gpo path
//
dwRet = ExpandEnvironmentStrings (LOCAL_GPO_DIRECTORY, szGPOPath, ARRAYSIZE(szGPOPath));
if (dwRet == 0)
{
xe = GetLastError();
DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to expand local gpo path with error %d. Exiting"), GetLastError() ));
goto Exit;
}
if (dwRet > ARRAYSIZE(szGPOPath))
{
xe = ERROR_INSUFFICIENT_BUFFER;
DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to expand local gpo path with error %d. Exiting"), (DWORD)xe ));
goto Exit;
}
//
// We check for the existence of gpt.ini -- note that if it does not exist,
// we will use the default state initialized earlier to represent this gpo --
// this mimics the behavior of the gp engine, which does not distinguish between
// different types of failures to access gpt.ini -- if access fails for any reason,
// it is treated as the local gpo in the default (clean installed) case
//
if (GetFileAttributesEx (szGPOPath, GetFileExInfoStandard, &fad) &&
(fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
bGptIniExists = TRUE;
} else {
DebugMsg((DM_VERBOSE, TEXT("GetGPOInfo: Local GPO's gpt.ini is not accessible, assuming default state.") ));
}
//
// Retrieve the gpo name
//
if (!LoadString (g_hDllInstance, IDS_LOCALGPONAME, szGPOName, ARRAYSIZE(szGPOName))) {
xe = GetLastError();
DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to local gpo name with error %d. Exiting"), GetLastError() ));
goto Exit;
}
DmAssert( lstrlen(szGPOPath) + lstrlen(TEXT("gpt.ini")) + 1 < MAX_PATH );
lpTemp = CheckSlash (szGPOPath);
hr = StringCchCopy (lpTemp, MAX_PATH - (lpTemp - szGPOPath), TEXT("gpt.ini"));
if ( FAILED(hr) ) {
xe = ERROR_INSUFFICIENT_BUFFER;
goto Exit;
}
//
// Read the gpt.ini file if it exists -- otherwise the default values will be used
//
if ( bGptIniExists ) {
bNoGpoData = FALSE;
//
// Check the functionalty version number
//
dwFunctionalityVersion = GetPrivateProfileInt(TEXT("General"), GPO_FUNCTIONALITY_VERSION, 2, szGPOPath);
if (dwFunctionalityVersion < 2) {
bOldGpoVersion = TRUE;
DebugMsg((DM_VERBOSE, TEXT("GetGPOInfo: GPO %s was created by an old version of the Group Policy Editor. It will be skipped."), szGPOName));
if (bVerbose) {
CEvents ev(FALSE, EVENT_GPO_TOO_OLD);
ev.AddArg(szGPOName); ev.Report();
}
}
//
// Check if this GPO is enabled
//
dwOptions = GetPrivateProfileInt(TEXT("General"), TEXT("Options"), 0, szGPOPath);
if (((dwFlags & GPO_LIST_FLAG_MACHINE) &&
(dwOptions & GPO_OPTION_DISABLE_MACHINE)) ||
(!(dwFlags & GPO_LIST_FLAG_MACHINE) &&
(dwOptions & GPO_OPTION_DISABLE_USER))) {
bDisabled = TRUE;
}
//
// Check if the version number is 0, if so there isn't any data
// in the GPO and we can skip it
//
dwVersion = GetPrivateProfileInt(TEXT("General"), TEXT("Version"), 0, szGPOPath);
if (dwFlags & GPO_LIST_FLAG_MACHINE) {
dwVersion = MAKELONG (LOWORD(dwVersion), LOWORD(dwVersion));
} else {
dwVersion = MAKELONG (HIWORD(dwVersion), HIWORD(dwVersion));
}
if (dwVersion == 0) {
bNoGpoData = TRUE;
DebugMsg((DM_VERBOSE, TEXT("GetGPOInfo: GPO %s doesn't contain any data since the version number is 0. It will be skipped."), szGPOName));
if (bVerbose) {
CEvents ev(FALSE, EVENT_GPO_NO_DATA);
ev.AddArg(szGPOName); ev.Report();
}
}
//
// Read list of extension guids
//
pszExtensions = (LPWSTR) LocalAlloc( LPTR, dwSize * sizeof(TCHAR) );
if ( pszExtensions == 0 ) {
xe = GetLastError();
DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to allocate memory.")));
goto Exit;
}
dwCount = GetPrivateProfileString( TEXT("General"),
dwFlags & GPO_LIST_FLAG_MACHINE ? GPO_MACHEXTENSION_NAMES
: GPO_USEREXTENSION_NAMES,
TEXT(""),
pszExtensions,
dwSize,
szGPOPath );
while ( dwCount == dwSize - 1 )
{
//
// Value has been truncated, so retry with larger buffer
//
LocalFree( pszExtensions );
dwSize *= 2;
pszExtensions = (LPWSTR) LocalAlloc( LPTR, dwSize * sizeof(TCHAR) );
if ( pszExtensions == 0 ) {
xe = GetLastError();
DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to allocate memory.")));
goto Exit;
}
dwCount = GetPrivateProfileString( TEXT("General"),
dwFlags & GPO_LIST_FLAG_MACHINE ? GPO_MACHEXTENSION_NAMES
: GPO_USEREXTENSION_NAMES,
TEXT(""),
pszExtensions,
dwSize,
szGPOPath );
}
if ( lstrcmpi( pszExtensions, TEXT("")) == 0 || lstrcmpi( pszExtensions, TEXT(" ")) == 0 ) {
//
// Extensions property was not found
//
LocalFree( pszExtensions );
pszExtensions = 0;
}
}
//
// Tack on the correct subdirectory name
//
DmAssert( lstrlen(szGPOPath) + lstrlen(TEXT("Machine")) + 1 < MAX_PATH );
if (dwFlags & GPO_LIST_FLAG_MACHINE) {
hr = StringCchCopy (lpTemp, MAX_PATH - (lpTemp - szGPOPath), TEXT("Machine"));
} else {
hr = StringCchCopy (lpTemp, MAX_PATH - (lpTemp - szGPOPath), TEXT("User"));
}
if ( FAILED(hr) ) {
xe = HRESULT_CODE(hr);
goto Exit;
}
//
// Add this to the list of paths
//
if ( bRsopLogging ) {
bOk = AddLocalGPO( ppSOMList );
if ( !bOk ) {
xe = GetLastError();
if ( pszExtensions )
LocalFree( pszExtensions );
DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to log Rsop data.")));
goto Exit;
}
bOk = AddGPOToRsopList( ppGpContainerList,
dwFlags,
TRUE,
TRUE,
bDisabled,
dwVersion,
L"LocalGPO",
szGPOPath,
szGPOName,
szGPOName,
0,
0,
TRUE,
0,
L"Local",
0 );
if ( !bOk ) {
xe = GetLastError();
if ( pszExtensions )
LocalFree( pszExtensions );
DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to log Rsop data.")));
goto Exit;
}
}
if ( !bDisabled && !bOldGpoVersion && !bNoGpoData )
{
bOk = AddGPO (&pGPONonForcedList, dwFlags, TRUE, TRUE, bDisabled, 0, dwVersion,
L"LocalGPO", szGPOPath,
szGPOName, szGPOName, pszExtensions, 0, 0, GPLinkMachine, L"Local", 0, TRUE,
FALSE, bVerbose, TRUE);
}
if ( pszExtensions )
LocalFree( pszExtensions );
if ( bOk ) {
if ( bVerbose ) {
if ( bDisabled || bOldGpoVersion || bNoGpoData ) {
CEvents ev(FALSE, EVENT_NO_LOCAL_GPO);
ev.Report();
}
else {
CEvents ev(FALSE, EVENT_FOUND_LOCAL_GPO);
ev.Report();
}
}
} else {
xe = GetLastError();
DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to add local group policy object to the list.")));
goto Exit;
}
}
//
// Merge the forced and nonforced lists together
//
if (pGPOForcedList && !pGPONonForcedList) {
*lpGPOList = pGPOForcedList;
} else if (!pGPOForcedList && pGPONonForcedList) {
*lpGPOList = pGPONonForcedList;
} else if (pGPOForcedList && pGPONonForcedList) {
lpGPO = pGPONonForcedList;
while (lpGPO->pNext) {
lpGPO = lpGPO->pNext;
}
lpGPO->pNext = pGPOForcedList;
pGPOForcedList->pPrev = lpGPO;
*lpGPOList = pGPONonForcedList;
}
//
// Success
//
bResult = TRUE;
Exit:
//
// Free any GPOs we found
//
if (!bResult) {
FreeGPOList( pGPOForcedList );
FreeGPOList( pGPONonForcedList );
}
//
// Free temporary OU list
//
while ( pDeferredOUList ) {
DNENTRY *pTemp = pDeferredOUList->pNext;
FreeDnEntry( pDeferredOUList );
pDeferredOUList = pTemp;
}
//
// Free temporary deferred GPO lists
//
FreeGPOList( pDeferredForcedList );
FreeGPOList( pDeferredNonForcedList );
if (pld) {
pldap_api->pfnldap_unbind (pld);
}
if ( pldMachine )
{
pldap_api->pfnldap_unbind( pldMachine );
}
DebugMsg((DM_VERBOSE, TEXT("GetGPOInfo: Leaving with %d"), bResult));
DebugMsg((DM_VERBOSE, TEXT("GetGPOInfo: ********************************")));
if ( hToken )
{
CloseHandle( hToken );
}
return bResult;
}
//*************************************************************
//
// GetGPOList()
//
// Purpose: Retreives the list of GPOs for the specified
// user or machine
//
// Parameters: hToken - User or machine token, if NULL,
// lpName and lpDCName must be supplied
// lpName - User or machine name in DN format,
// if hToken is supplied, this must be NULL
// lpHostName - Host name. This should be a domain's
// dn name for best performance. Otherwise
// it can also be a DC name. If hToken is supplied,
// this must be NULL
// lpComputerName - Computer named used to determine site
// information. Can be NULL which means
// use the local machine
// dwFlags - Flags field
// pGPOList - Address of a pointer which receives
// the link list of GPOs
//
// Return: TRUE if successful
// FALSE if an error occurs
//
//*************************************************************
BOOL WINAPI GetGPOList (HANDLE hToken, LPCTSTR lpName, LPCTSTR lpHostName,
LPCTSTR lpComputerName, DWORD dwFlags,
PGROUP_POLICY_OBJECT *pGPOList)
{
PDOMAIN_CONTROLLER_INFO pDCI = NULL;
BOOL bResult = FALSE;
LPTSTR lpDomainDN, lpDNName, lpTemp, lpUserName = NULL;
DWORD dwResult;
HANDLE hOldToken = 0;
PNETAPI32_API pNetAPI32;
LPSCOPEOFMGMT lpSOMList = 0; // LSDOU list
LPGPCONTAINER lpGpContainerList = 0; // GP container list
HRESULT hr;
OLE32_API *pOle32Api = NULL;
XLastError xe;
LPWSTR szSiteName = NULL;
BOOL bInitializedCOM = FALSE;
//
// mask off the flags that are used internally.
//
dwFlags &= FLAG_INTERNAL_MASK;
//
// Verbose output
//
DebugMsg((DM_VERBOSE, TEXT("GetGPOList: Entering.")));
DebugMsg((DM_VERBOSE, TEXT("GetGPOList: hToken = 0x%x"), (hToken ? hToken : 0)));
DebugMsg((DM_VERBOSE, TEXT("GetGPOList: lpName = <%s>"), (lpName ? lpName : TEXT("NULL"))));
DebugMsg((DM_VERBOSE, TEXT("GetGPOList: lpHostName = <%s>"), (lpHostName ? lpHostName : TEXT("NULL"))));
DebugMsg((DM_VERBOSE, TEXT("GetGPOList: dwFlags = 0x%x"), dwFlags));
//
// Check parameters
//
if (hToken) {
if (lpName || lpHostName) {
xe = ERROR_INVALID_PARAMETER;
DebugMsg((DM_WARNING, TEXT("GetGPOList: lpName and lpHostName must be NULL")));
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
} else {
if (!lpName || !lpHostName) {
xe = ERROR_INVALID_PARAMETER;
DebugMsg((DM_WARNING, TEXT("GetGPOList: lpName and lpHostName must be valid")));
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
}
// check if there is space in the lpHostName
if (lpHostName)
{
// fixing bug 567835
// check if there is space in the lpHostName
LPCTSTR lpPtr = lpHostName;
while (*lpPtr) {
if (*lpPtr == L' ')
{
xe = ERROR_INVALID_PARAMETER;
DebugMsg((DM_WARNING, TEXT("GetGPOInfo: lpHostName shld not contain space in it")));
return FALSE;
}
lpPtr++;
}
}
if (!pGPOList) {
xe = ERROR_INVALID_PARAMETER;
DebugMsg((DM_WARNING, TEXT("GetGPOList: pGPOList is null")));
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
//
// Load netapi32
//
pNetAPI32 = LoadNetAPI32();
if (!pNetAPI32) {
xe = GetLastError();
DebugMsg((DM_WARNING, TEXT("GetGPOList: Failed to load netapi32 with %d."),
GetLastError()));
goto Exit;
}
//
// If an hToken was offered, then we need to get the name and
// domain DN name
//
if (hToken) {
//
// Impersonate the user / machine
//
if (!ImpersonateUser(hToken, &hOldToken)) {
xe = GetLastError();
DebugMsg((DM_WARNING, TEXT("GetGPOList: Failed to impersonate user")));
return FALSE;
}
//
// Get the username in DN format
//
lpUserName = MyGetUserName (NameFullyQualifiedDN);
if (!lpUserName) {
xe = GetLastError();
DebugMsg((DM_WARNING, TEXT("GetGPOList: MyGetUserName failed for DN style name with %d"),
GetLastError()));
CEvents ev(TRUE, EVENT_FAILED_USERNAME);
ev.AddArgWin32Error(GetLastError()); ev.Report();
goto Exit;
}
lpDNName = lpUserName;
DebugMsg((DM_VERBOSE, TEXT("GetGPOList: Queried lpDNName = <%s>"), lpDNName));
//
// Get the dns domain name
//
lpDomainDN = MyGetDomainDNSName ();
if (!lpDomainDN) {
xe = GetLastError();
DebugMsg((DM_WARNING, TEXT("GetGPOList: MyGetUserName failed for dns domain name with %d"),
GetLastError()));
CEvents ev(TRUE, EVENT_FAILED_USERNAME);
ev.AddArgWin32Error(GetLastError()); ev.Report();
goto Exit;
}
//
// Check this domain for a DC
//
dwResult = pNetAPI32->pfnDsGetDcName (NULL, lpDomainDN, NULL, NULL,
DS_DIRECTORY_SERVICE_PREFERRED |
DS_RETURN_DNS_NAME,
&pDCI);
if (dwResult != ERROR_SUCCESS) {
xe = dwResult;
DebugMsg((DM_WARNING, TEXT("GetGPOList: DSGetDCName failed with %d for <%s>"),
dwResult, lpDomainDN));
goto Exit;
}
//
// Found a DC, does it have a DS ?
//
if (!(pDCI->Flags & DS_DS_FLAG)) {
xe = ERROR_DS_DS_REQUIRED;
pNetAPI32->pfnNetApiBufferFree(pDCI);
DebugMsg((DM_WARNING, TEXT("GetGPOList: The domain <%s> does not have a DS"),
lpDomainDN));
goto Exit;
}
pNetAPI32->pfnNetApiBufferFree(pDCI);
} else {
//
// Use the server and DN name passed in
//
lpDomainDN = (LPTSTR)lpHostName;
lpDNName = (LPTSTR)lpName;
}
pOle32Api = LoadOle32Api();
if ( pOle32Api == NULL ) {
xe = GetLastError();
DebugMsg((DM_WARNING, TEXT("GetGPOList: Failed to load ole32.dll.") ));
goto Exit;
}
hr = pOle32Api->pfnCoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
if ( SUCCEEDED(hr) )
{
bInitializedCOM = TRUE;
}
//
// If this thread is already initialized, this is fine -- we will ignore
// this since we are safely initialized, we just need to remember not
// to try to uninitialize the thread later
//
if ( RPC_E_CHANGED_MODE == hr )
{
hr = S_OK;
}
if ( FAILED(hr) ) {
xe = HRESULT_CODE(hr);
DebugMsg((DM_WARNING, TEXT("GetGPOList: CoInitializeEx failed with 0x%x."), hr ));
goto Exit;
}
hr = CoInitializeSecurity(NULL, -1, NULL, NULL,
RPC_C_AUTHN_LEVEL_DEFAULT, /* this should be the current value */
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL, EOAC_NONE, NULL);
if ( FAILED(hr) ) {
DebugMsg((DM_WARNING, TEXT("GetGPOList: CoInitializeSecurity failed with 0x%x"), hr ));
}
//
// Call to get the list of GPOs
//
dwResult = pNetAPI32->pfnDsGetSiteName(lpComputerName, &szSiteName);
if ( dwResult != ERROR_SUCCESS )
{
if ( dwResult != ERROR_NO_SITENAME )
{
xe = dwResult;
DebugMsg((DM_WARNING, TEXT("GetGPOList: DSGetSiteName failed, exiting. 0x%x"), dwResult ));
goto Exit;
}
szSiteName = 0;
}
{
CLocator locator;
// Clocator has a bunch of OLE interfaces.
// It should be released before CoUninit gets called
bResult = GetGPOInfo( dwFlags,
lpDomainDN,
lpDNName,
lpComputerName,
pGPOList,
&lpSOMList,
&lpGpContainerList,
pNetAPI32,
FALSE,
0,
szSiteName,
0,
&locator );
if (!bResult) {
xe = GetLastError();
}
}
Exit:
if ( bInitializedCOM )
{
pOle32Api->pfnCoUnInitialize();
}
//
// Stop impersonating if a hToken was given
//
if ( hOldToken ) {
RevertToUser(&hOldToken);
}
if (lpDomainDN) {
LocalFree (lpDomainDN);
}
if (lpUserName) {
LocalFree (lpUserName);
}
if ( szSiteName )
{
pNetAPI32->pfnNetApiBufferFree( szSiteName );
}
FreeSOMList( lpSOMList );
FreeGpContainerList( lpGpContainerList );
DebugMsg((DM_VERBOSE, TEXT("GetGPOList: Leaving with %d"), bResult));
return bResult;
}