//************************************************************* // // Group Policy Support - Getting the list of gpos // // Microsoft Confidential // Copyright (c) Microsoft Corporation 1997-1998 // All rights reserved // //************************************************************* #include "gphdr.h" #include //************************************************************* // // 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; }