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

  1. //*************************************************************
  2. //
  3. // Group Policy Support - Getting the list of gpos
  4. //
  5. // Microsoft Confidential
  6. // Copyright (c) Microsoft Corporation 1997-1998
  7. // All rights reserved
  8. //
  9. //*************************************************************
  10. #include "gphdr.h"
  11. #include <strsafe.h>
  12. //*************************************************************
  13. //
  14. // DsQuoteSearchFilter()
  15. //
  16. //
  17. // Comment: This function takes a DN and returns a version
  18. // of the DN escaped according to RFC's 2253 and 2254
  19. //
  20. // Return: A pointer to the quoted string, which must be
  21. // freed by the caller. If the function fails, the
  22. // return value is 0.
  23. //
  24. //*************************************************************
  25. LPWSTR
  26. DsQuoteSearchFilter( LPCWSTR szUDN )
  27. {
  28. DmAssert(NULL != szUDN );
  29. if (NULL == szUDN)
  30. return NULL;
  31. DWORD cUDN = wcslen( szUDN );
  32. LPWSTR szQDN = 0, szTemp = 0;;
  33. HRESULT hr = S_OK;
  34. //
  35. // Note that the maximum length of the quoted string would result
  36. // if every single character in the DN needed to be escaped. Since
  37. // the escaped characters are of the form '\nn', the escaped string
  38. // could be at most 3 times the size of the original string
  39. //
  40. if ( cUDN )
  41. {
  42. szTemp = szQDN = (LPWSTR) LocalAlloc( LPTR, ( cUDN * 3 + 1 ) * sizeof( WCHAR ) );
  43. }
  44. if ( !szQDN )
  45. {
  46. return 0;
  47. }
  48. while ( *szUDN )
  49. {
  50. WCHAR szBuffer[16];
  51. if ( *szUDN == L'*' || *szUDN == L'(' || *szUDN == L')' || !*szUDN )
  52. {
  53. //
  54. // convert special characters to \NN
  55. //
  56. *szQDN++ = L'\\';
  57. DWORD dwQDNLength = cUDN * 3 + 1 - (DWORD) (szQDN - szTemp);
  58. hr = StringCchCat( szQDN, dwQDNLength, _itow( *szUDN++, szBuffer, 16 ) );
  59. ASSERT(SUCCEEDED(hr));
  60. szQDN += 2;
  61. }
  62. else
  63. {
  64. *szQDN++ = *szUDN++;
  65. }
  66. }
  67. *szQDN = 0;
  68. return szTemp;
  69. }
  70. //*************************************************************
  71. //
  72. // GetGPOInfo()
  73. //
  74. // Purpose: Gets the GPO info for this threads token.
  75. //
  76. // Parameters: dwFlags - GPO_LIST_FLAG_* from userenv.h
  77. // lpHostName - Domain DN name or DC server name
  78. // lpDNName - User or Machine DN name
  79. // lpComputerName - Computer name used for site look up
  80. // lpGPOList - Receives the list of GROUP_POLICY_OBJECTs
  81. // ppSOMList - List of LSDOUs returned here
  82. // ppGpContainerList - List of Gp containers returned here
  83. // pNetAPI32 - Netapi32 function table
  84. // bMachineTokenOK - Ok to query for the machine token
  85. // pRsopToken - Rsop security token
  86. // pGpoFilter - Gpo filter
  87. // pLocator - WMI interfaces
  88. //
  89. // Comment: This is a link list of GROUP_POLICY_OBJECTs. Each can be
  90. // free'ed with LocalFree() or calling FreeGPOList()
  91. //
  92. // The processing sequence is:
  93. //
  94. // Local Forest Site Domain OrganizationalUnit
  95. //
  96. // Note that we process this list backwards to get the
  97. // correct sequencing for the force flag.
  98. //
  99. // Return: TRUE if successful
  100. // FALSE if an error occurs
  101. //
  102. //*************************************************************
  103. BOOL GetGPOInfo(DWORD dwFlags,
  104. LPTSTR lpHostName,
  105. LPTSTR lpDNName,
  106. LPCTSTR lpComputerName,
  107. PGROUP_POLICY_OBJECT *lpGPOList,
  108. LPSCOPEOFMGMT *ppSOMList,
  109. LPGPCONTAINER *ppGpContainerList,
  110. PNETAPI32_API pNetAPI32,
  111. BOOL bMachineTokenOk,
  112. PRSOPTOKEN pRsopToken,
  113. LPWSTR pwszSiteName,
  114. CGpoFilter *pGpoFilter,
  115. CLocator *pLocator )
  116. {
  117. PGROUP_POLICY_OBJECT pGPOForcedList = NULL, pGPONonForcedList = NULL;
  118. PLDAP pld = NULL;
  119. ULONG ulResult;
  120. BOOL bResult = FALSE;
  121. BOOL bBlock = FALSE;
  122. LPTSTR lpDSObject, lpTemp;
  123. PLDAPMessage pLDAPMsg = NULL;
  124. TCHAR szGPOPath[MAX_PATH];
  125. TCHAR szGPOName[50];
  126. BOOL bVerbose;
  127. DWORD dwVersion, dwOptions;
  128. TCHAR szNamingContext[] = TEXT("configurationNamingContext");
  129. TCHAR szSDProperty[] = TEXT("nTSecurityDescriptor"); // this is unused currently
  130. LPTSTR lpAttr[] = { szNamingContext,
  131. szSDProperty,
  132. 0 };
  133. PGROUP_POLICY_OBJECT lpGPO, lpGPOTemp;
  134. WIN32_FILE_ATTRIBUTE_DATA fad;
  135. PLDAP_API pldap_api;
  136. HANDLE hToken = NULL, hTempToken;
  137. DWORD dwFunctionalityVersion;
  138. PGROUP_POLICY_OBJECT pDeferredForcedList = NULL, pDeferredNonForcedList = NULL;
  139. DNENTRY *pDeferredOUList = NULL; // List of deferred OUs
  140. TCHAR* szDN;
  141. PSECUR32_API pSecur32Api;
  142. BOOL bAddedOU = FALSE;
  143. PLDAP pldMachine = 0;
  144. VOID *pData;
  145. BOOL bOwnSiteName = FALSE;
  146. BOOL bRsopLogging = (ppSOMList != 0);
  147. BOOL bRsopPlanningMode = (pRsopToken != 0);
  148. XLastError xe;
  149. HRESULT hr = S_OK;
  150. //
  151. // Verbose output
  152. //
  153. DebugMsg((DM_VERBOSE, TEXT("GetGPOInfo: ********************************")));
  154. DebugMsg((DM_VERBOSE, TEXT("GetGPOInfo: Entering...")));
  155. //
  156. // Start with lpGPOList being a pointer to null
  157. //
  158. *lpGPOList = NULL;
  159. DmAssert( *ppSOMList == NULL );
  160. DmAssert( *ppGpContainerList == NULL );
  161. //
  162. // Check if we should be verbose to the event log
  163. //
  164. bVerbose = CheckForVerbosePolicy();
  165. //
  166. // Load the secur32 api
  167. //
  168. pSecur32Api = LoadSecur32();
  169. if (!pSecur32Api) {
  170. xe = GetLastError();
  171. DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to load secur32 api.")));
  172. goto Exit;
  173. }
  174. //
  175. // Load the ldap api
  176. //
  177. pldap_api = LoadLDAP();
  178. if (!pldap_api) {
  179. xe = GetLastError();
  180. DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to load ldap api.")));
  181. goto Exit;
  182. }
  183. //=========================================================================
  184. //
  185. // If we don't have a DS server or user / machine name, we can
  186. // skip the DS stuff and only check for a local GPO
  187. //
  188. //=========================================================================
  189. if (!lpHostName || !lpDNName) {
  190. DebugMsg((DM_VERBOSE, TEXT("GetGPOInfo: lpHostName or lpDNName is NULL. Skipping DS stuff.")));
  191. goto CheckLocal;
  192. }
  193. //
  194. // Get the user or machine's token
  195. //
  196. if (bMachineTokenOk && (dwFlags & GPO_LIST_FLAG_MACHINE)) {
  197. hToken = GetMachineToken();
  198. if (!hToken) {
  199. xe = GetLastError();
  200. DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to get the machine token with %d"),
  201. GetLastError()));
  202. CEvents ev(TRUE, EVENT_FAILED_MACHINE_TOKEN);
  203. ev.AddArgWin32Error(xe); ev.Report();
  204. goto Exit;
  205. }
  206. } else {
  207. if (!OpenThreadToken (GetCurrentThread(), TOKEN_IMPERSONATE | TOKEN_READ | TOKEN_DUPLICATE,
  208. TRUE, &hTempToken)) {
  209. if (!OpenProcessToken(GetCurrentProcess(), TOKEN_IMPERSONATE | TOKEN_READ | TOKEN_DUPLICATE,
  210. &hTempToken)) {
  211. xe = GetLastError();
  212. DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to get a token with %d"),
  213. GetLastError()));
  214. goto Exit;
  215. }
  216. }
  217. //
  218. // Duplicate it so it can be used for impersonation
  219. //
  220. if (!DuplicateTokenEx(hTempToken, TOKEN_QUERY, // Fixing bug 568191.
  221. NULL, SecurityImpersonation, TokenImpersonation,
  222. &hToken))
  223. {
  224. xe = GetLastError();
  225. DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to duplicate the token with %d"),
  226. GetLastError()));
  227. CloseHandle (hTempToken);
  228. goto Exit;
  229. }
  230. CloseHandle (hTempToken);
  231. }
  232. //
  233. // Get a connection to the DS
  234. //
  235. if ((lpHostName[0] == TEXT('\\')) && (lpHostName[1] == TEXT('\\'))) {
  236. lpHostName = lpHostName + 2;
  237. }
  238. pld = pldap_api->pfnldap_init( lpHostName, LDAP_PORT);
  239. if (!pld) {
  240. xe = GetLastError();
  241. DebugMsg((DM_WARNING, TEXT("GetGPOInfo: ldap_open for <%s> failed with = 0x%x or %d"),
  242. lpHostName, pldap_api->pfnLdapGetLastError(), GetLastError()));
  243. CEvents ev(TRUE, EVENT_FAILED_DS_CONNECT);
  244. ev.AddArg(lpHostName); ev.AddArgLdapError(pldap_api->pfnLdapGetLastError()); ev.Report();
  245. goto Exit;
  246. }
  247. DebugMsg((DM_VERBOSE, TEXT("GetGPOInfo: Server connection established.")));
  248. //
  249. // Turn on Packet integrity flag
  250. //
  251. pData = (VOID *) LDAP_OPT_ON;
  252. ulResult = pldap_api->pfnldap_set_option(pld, LDAP_OPT_SIGN, &pData);
  253. if (ulResult != LDAP_SUCCESS) {
  254. xe = pldap_api->pfnLdapMapErrorToWin32(ulResult);
  255. DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to turn on LDAP_OPT_SIGN with %d"), ulResult));
  256. goto Exit;
  257. }
  258. ulResult = pldap_api->pfnldap_connect(pld, 0);
  259. if (ulResult != LDAP_SUCCESS) {
  260. xe = pldap_api->pfnLdapMapErrorToWin32(ulResult);
  261. DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to connect %s with %d"), lpHostName, ulResult));
  262. pldap_api->pfnldap_unbind(pld);
  263. pld = 0;
  264. goto Exit;
  265. }
  266. //
  267. // Bind to the DS.
  268. //
  269. if ( !bRsopPlanningMode && (dwFlags & GPO_LIST_FLAG_MACHINE) ) {
  270. //
  271. // For machine policies specifically ask for Kerberos as the only authentication
  272. // mechanism. Otherwise if Kerberos were to fail for some reason, then NTLM is used
  273. // and localsystem context has no real credentials, which means that we won't get
  274. // any GPOs back.
  275. //
  276. SEC_WINNT_AUTH_IDENTITY_EXW secIdentity;
  277. secIdentity.Version = SEC_WINNT_AUTH_IDENTITY_VERSION;
  278. secIdentity.Length = sizeof(SEC_WINNT_AUTH_IDENTITY_EXW);
  279. secIdentity.User = 0;
  280. secIdentity.UserLength = 0;
  281. secIdentity.Domain = 0;
  282. secIdentity.DomainLength = 0;
  283. secIdentity.Password = 0;
  284. secIdentity.PasswordLength = 0;
  285. secIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
  286. secIdentity.PackageList = wszKerberos;
  287. secIdentity.PackageListLength = lstrlen( wszKerberos );
  288. ulResult = pldap_api->pfnldap_bind_s (pld, NULL, (WCHAR *)&secIdentity, LDAP_AUTH_SSPI);
  289. } else
  290. ulResult = pldap_api->pfnldap_bind_s (pld, NULL, NULL, LDAP_AUTH_SSPI);
  291. if (ulResult != LDAP_SUCCESS) {
  292. xe = pldap_api->pfnLdapMapErrorToWin32(ulResult);
  293. DebugMsg((DM_WARNING, TEXT("GetGPOInfo: ldap_bind_s failed with = <%d>"),
  294. ulResult));
  295. CEvents ev(TRUE, EVENT_FAILED_DS_BIND);
  296. ev.AddArg(lpHostName); ev.AddArgLdapError(ulResult); ev.Report();
  297. goto Exit;
  298. }
  299. DebugMsg((DM_VERBOSE, TEXT("GetGPOInfo: Bound successfully.")));
  300. //=========================================================================
  301. //
  302. // Check the organizational units and domain for policy
  303. //
  304. //=========================================================================
  305. if (!(dwFlags & GPO_LIST_FLAG_SITEONLY)) {
  306. //
  307. // Loop through the DN Name to find each OU or the domain
  308. //
  309. lpDSObject = lpDNName;
  310. while (*lpDSObject) {
  311. //
  312. // See if the DN name starts with OU=
  313. //
  314. if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE,
  315. lpDSObject, 3, TEXT("OU="), 3) == CSTR_EQUAL) {
  316. if ( !AddOU( &pDeferredOUList, lpDSObject, GPLinkOrganizationalUnit ) ) {
  317. xe = GetLastError();
  318. goto Exit;
  319. }
  320. }
  321. //
  322. // See if the DN name starts with DC=
  323. //
  324. else if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE,
  325. lpDSObject, 3, TEXT("DC="), 3) == CSTR_EQUAL) {
  326. if ( !AddOU( &pDeferredOUList, lpDSObject, GPLinkDomain ) ) {
  327. xe = GetLastError();
  328. goto Exit;
  329. }
  330. //
  331. // Now that we've found a DN name that starts with DC=
  332. // we exit the loop now.
  333. //
  334. break;
  335. }
  336. //
  337. // Move to the next chunk of the DN name
  338. //
  339. while (*lpDSObject && (*lpDSObject != TEXT(','))) {
  340. lpDSObject++;
  341. }
  342. if (*lpDSObject == TEXT(',')) {
  343. lpDSObject++;
  344. }
  345. }
  346. //
  347. // Evaluate deferred OUs with single Ldap query
  348. //
  349. if ( !EvaluateDeferredOUs( pDeferredOUList,
  350. dwFlags,
  351. hToken,
  352. &pDeferredForcedList,
  353. &pDeferredNonForcedList,
  354. ppSOMList,
  355. ppGpContainerList,
  356. bVerbose,
  357. pld,
  358. pldap_api,
  359. &bBlock,
  360. pRsopToken ) )
  361. {
  362. xe = GetLastError();
  363. DebugMsg((DM_WARNING, TEXT("GetGPOInfo: EvaluateDeferredOUs failed. Exiting") ));
  364. goto Exit;
  365. }
  366. }
  367. //=========================================================================
  368. //
  369. // Check the site object for policy
  370. //
  371. //=========================================================================
  372. //
  373. // Now we need to query for the domain name.
  374. //
  375. //
  376. // Now we need to query for the domain name. This is done by
  377. // reading the operational attribute configurationNamingContext
  378. //
  379. if (pwszSiteName) {
  380. pldMachine = GetMachineDomainDS( pNetAPI32, pldap_api );
  381. if ( pldMachine )
  382. {
  383. pLDAPMsg = 0;
  384. ulResult = pldap_api->pfnldap_search_s( pldMachine,
  385. TEXT(""),
  386. LDAP_SCOPE_BASE,
  387. TEXT("(objectClass=*)"),
  388. lpAttr,
  389. FALSE,
  390. &pLDAPMsg);
  391. if ( ulResult == LDAP_SUCCESS )
  392. {
  393. LPTSTR* pszValues = pldap_api->pfnldap_get_values( pldMachine, pLDAPMsg, szNamingContext );
  394. if ( pszValues )
  395. {
  396. LPWSTR szSite;
  397. WCHAR szSiteFmt[] = TEXT("CN=%s,CN=Sites,%s");
  398. //
  399. // Combine the domain name + site name to get the full
  400. // DS object path
  401. //
  402. DWORD dwSiteLen = lstrlen(pwszSiteName) + lstrlen(*pszValues) + lstrlen(szSiteFmt) + 1;
  403. szSite = (LPWSTR) LocalAlloc( LPTR, (dwSiteLen) * sizeof(WCHAR));
  404. if (szSite)
  405. {
  406. (void) StringCchPrintf( szSite, dwSiteLen, szSiteFmt, pwszSiteName, *pszValues );
  407. if (SearchDSObject (szSite, dwFlags, hToken, &pDeferredForcedList, &pDeferredNonForcedList,
  408. ppSOMList, ppGpContainerList,
  409. bVerbose, GPLinkSite, pldMachine,
  410. pldap_api, NULL, &bBlock, pRsopToken )) {
  411. bAddedOU = TRUE;
  412. } else {
  413. xe = GetLastError();
  414. DebugMsg((DM_WARNING, TEXT("GetGPOInfo: SearchDSObject failed. Exiting.")));
  415. }
  416. LocalFree(szSite);
  417. }
  418. else
  419. {
  420. xe = ERROR_OUTOFMEMORY;
  421. }
  422. pldap_api->pfnldap_value_free( pszValues );
  423. }
  424. else
  425. {
  426. xe = GetLastError();
  427. DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to get values.")));
  428. }
  429. pldap_api->pfnldap_msgfree( pLDAPMsg );
  430. }
  431. else
  432. {
  433. xe = pldap_api->pfnLdapMapErrorToWin32(ulResult);
  434. DebugMsg((DM_WARNING, TEXT("GetGPOInfo: ldap_search_s failed with = <%d>"), ulResult) );
  435. CEvents ev(TRUE, EVENT_FAILED_ROOT_SEARCH);
  436. ev.AddArgLdapError(ulResult); ev.Report();
  437. }
  438. }
  439. if ( !bAddedOU )
  440. {
  441. goto Exit;
  442. }
  443. }
  444. #ifdef FGPO_SUPPORTED
  445. //=========================================================================
  446. //
  447. // Now query for the forest GPO
  448. //
  449. //=========================================================================
  450. pLDAPMsg = 0;
  451. ulResult = pldap_api->pfnldap_search_s( pld,
  452. TEXT(""),
  453. LDAP_SCOPE_BASE,
  454. TEXT("(objectClass=*)"),
  455. lpAttr,
  456. FALSE,
  457. &pLDAPMsg);
  458. if ( ulResult == LDAP_SUCCESS )
  459. {
  460. LPTSTR* pszValues = pldap_api->pfnldap_get_values( pld, pLDAPMsg, szNamingContext );
  461. if (pszValues) {
  462. if (SearchDSObject (*pszValues, dwFlags, hToken, &pDeferredForcedList, &pDeferredNonForcedList,
  463. ppSOMList, ppGpContainerList,
  464. bVerbose, GPLinkForest, pld,
  465. pldap_api, NULL, &bBlock, pRsopToken )) {
  466. bAddedOU = TRUE;
  467. }
  468. else {
  469. xe = GetLastError();
  470. DebugMsg((DM_WARNING, TEXT("GetGPOInfo: SearchDSObject failed for forest GPOs. Exiting.")));
  471. }
  472. pldap_api->pfnldap_value_free( pszValues );
  473. }
  474. else
  475. {
  476. xe = GetLastError();
  477. DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to get values for user config container.")));
  478. }
  479. pldap_api->pfnldap_msgfree( pLDAPMsg );
  480. }
  481. else
  482. {
  483. xe = pldap_api->pfnLdapMapErrorToWin32(ulResult);
  484. DebugMsg((DM_WARNING, TEXT("GetGPOInfo: ldap_search_s failed with = <%d>"), ulResult) );
  485. CEvents ev(TRUE, EVENT_FAILED_ROOT_SEARCH);
  486. ev.AddArgLdapError(ulResult); ev.Report();
  487. }
  488. if ( !bAddedOU )
  489. {
  490. goto Exit;
  491. }
  492. #endif
  493. CheckLocal:
  494. //
  495. // Evaluate all GPOs deferred so far with single Ldap query
  496. //
  497. if ( !EvaluateDeferredGPOs( pld,
  498. pldap_api,
  499. lpHostName,
  500. dwFlags,
  501. hToken,
  502. bVerbose,
  503. pDeferredForcedList,
  504. pDeferredNonForcedList,
  505. &pGPOForcedList,
  506. &pGPONonForcedList,
  507. ppGpContainerList,
  508. pRsopToken,
  509. pGpoFilter, pLocator ) )
  510. {
  511. xe = GetLastError();
  512. DebugMsg((DM_WARNING, TEXT("GetGPOInfo: EvaluateDeferredGPOs failed. Exiting") ));
  513. goto Exit;
  514. }
  515. //=========================================================================
  516. //
  517. // Check if we have a local GPO. If so, add it to the list. In planning mode
  518. // local Gpo processing is omitted because planning mode is generated on a DC
  519. // and local Gpo should refer to Gpo on the target computer.
  520. //
  521. //=========================================================================
  522. if (!bRsopPlanningMode && !(dwFlags & GPO_LIST_FLAG_SITEONLY)) {
  523. BOOL bDisabled = FALSE;
  524. BOOL bOldGpoVersion = FALSE;
  525. BOOL bNoGpoData = FALSE;
  526. DWORD dwSize = MAX_PATH;
  527. DWORD dwCount = 0;
  528. BOOL bOk = FALSE;
  529. TCHAR *pszExtensions = 0;
  530. BOOL bGptIniExists = FALSE;
  531. DWORD dwRet;
  532. //
  533. // If the gpt.ini doesn't exist because this is a clean installed machine,
  534. // we manufacture default state for it here -- these values must be
  535. // initialized since they normally require the gpt.ini
  536. //
  537. dwFunctionalityVersion = 2;
  538. dwOptions = 0;
  539. bDisabled = FALSE;
  540. dwVersion = 0;
  541. bNoGpoData = TRUE;
  542. //
  543. // Retrieve the gpo path
  544. //
  545. dwRet = ExpandEnvironmentStrings (LOCAL_GPO_DIRECTORY, szGPOPath, ARRAYSIZE(szGPOPath));
  546. if (dwRet == 0)
  547. {
  548. xe = GetLastError();
  549. DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to expand local gpo path with error %d. Exiting"), GetLastError() ));
  550. goto Exit;
  551. }
  552. if (dwRet > ARRAYSIZE(szGPOPath))
  553. {
  554. xe = ERROR_INSUFFICIENT_BUFFER;
  555. DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to expand local gpo path with error %d. Exiting"), (DWORD)xe ));
  556. goto Exit;
  557. }
  558. //
  559. // We check for the existence of gpt.ini -- note that if it does not exist,
  560. // we will use the default state initialized earlier to represent this gpo --
  561. // this mimics the behavior of the gp engine, which does not distinguish between
  562. // different types of failures to access gpt.ini -- if access fails for any reason,
  563. // it is treated as the local gpo in the default (clean installed) case
  564. //
  565. if (GetFileAttributesEx (szGPOPath, GetFileExInfoStandard, &fad) &&
  566. (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  567. bGptIniExists = TRUE;
  568. } else {
  569. DebugMsg((DM_VERBOSE, TEXT("GetGPOInfo: Local GPO's gpt.ini is not accessible, assuming default state.") ));
  570. }
  571. //
  572. // Retrieve the gpo name
  573. //
  574. if (!LoadString (g_hDllInstance, IDS_LOCALGPONAME, szGPOName, ARRAYSIZE(szGPOName))) {
  575. xe = GetLastError();
  576. DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to local gpo name with error %d. Exiting"), GetLastError() ));
  577. goto Exit;
  578. }
  579. DmAssert( lstrlen(szGPOPath) + lstrlen(TEXT("gpt.ini")) + 1 < MAX_PATH );
  580. lpTemp = CheckSlash (szGPOPath);
  581. hr = StringCchCopy (lpTemp, MAX_PATH - (lpTemp - szGPOPath), TEXT("gpt.ini"));
  582. if ( FAILED(hr) ) {
  583. xe = ERROR_INSUFFICIENT_BUFFER;
  584. goto Exit;
  585. }
  586. //
  587. // Read the gpt.ini file if it exists -- otherwise the default values will be used
  588. //
  589. if ( bGptIniExists ) {
  590. bNoGpoData = FALSE;
  591. //
  592. // Check the functionalty version number
  593. //
  594. dwFunctionalityVersion = GetPrivateProfileInt(TEXT("General"), GPO_FUNCTIONALITY_VERSION, 2, szGPOPath);
  595. if (dwFunctionalityVersion < 2) {
  596. bOldGpoVersion = TRUE;
  597. DebugMsg((DM_VERBOSE, TEXT("GetGPOInfo: GPO %s was created by an old version of the Group Policy Editor. It will be skipped."), szGPOName));
  598. if (bVerbose) {
  599. CEvents ev(FALSE, EVENT_GPO_TOO_OLD);
  600. ev.AddArg(szGPOName); ev.Report();
  601. }
  602. }
  603. //
  604. // Check if this GPO is enabled
  605. //
  606. dwOptions = GetPrivateProfileInt(TEXT("General"), TEXT("Options"), 0, szGPOPath);
  607. if (((dwFlags & GPO_LIST_FLAG_MACHINE) &&
  608. (dwOptions & GPO_OPTION_DISABLE_MACHINE)) ||
  609. (!(dwFlags & GPO_LIST_FLAG_MACHINE) &&
  610. (dwOptions & GPO_OPTION_DISABLE_USER))) {
  611. bDisabled = TRUE;
  612. }
  613. //
  614. // Check if the version number is 0, if so there isn't any data
  615. // in the GPO and we can skip it
  616. //
  617. dwVersion = GetPrivateProfileInt(TEXT("General"), TEXT("Version"), 0, szGPOPath);
  618. if (dwFlags & GPO_LIST_FLAG_MACHINE) {
  619. dwVersion = MAKELONG (LOWORD(dwVersion), LOWORD(dwVersion));
  620. } else {
  621. dwVersion = MAKELONG (HIWORD(dwVersion), HIWORD(dwVersion));
  622. }
  623. if (dwVersion == 0) {
  624. bNoGpoData = TRUE;
  625. DebugMsg((DM_VERBOSE, TEXT("GetGPOInfo: GPO %s doesn't contain any data since the version number is 0. It will be skipped."), szGPOName));
  626. if (bVerbose) {
  627. CEvents ev(FALSE, EVENT_GPO_NO_DATA);
  628. ev.AddArg(szGPOName); ev.Report();
  629. }
  630. }
  631. //
  632. // Read list of extension guids
  633. //
  634. pszExtensions = (LPWSTR) LocalAlloc( LPTR, dwSize * sizeof(TCHAR) );
  635. if ( pszExtensions == 0 ) {
  636. xe = GetLastError();
  637. DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to allocate memory.")));
  638. goto Exit;
  639. }
  640. dwCount = GetPrivateProfileString( TEXT("General"),
  641. dwFlags & GPO_LIST_FLAG_MACHINE ? GPO_MACHEXTENSION_NAMES
  642. : GPO_USEREXTENSION_NAMES,
  643. TEXT(""),
  644. pszExtensions,
  645. dwSize,
  646. szGPOPath );
  647. while ( dwCount == dwSize - 1 )
  648. {
  649. //
  650. // Value has been truncated, so retry with larger buffer
  651. //
  652. LocalFree( pszExtensions );
  653. dwSize *= 2;
  654. pszExtensions = (LPWSTR) LocalAlloc( LPTR, dwSize * sizeof(TCHAR) );
  655. if ( pszExtensions == 0 ) {
  656. xe = GetLastError();
  657. DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to allocate memory.")));
  658. goto Exit;
  659. }
  660. dwCount = GetPrivateProfileString( TEXT("General"),
  661. dwFlags & GPO_LIST_FLAG_MACHINE ? GPO_MACHEXTENSION_NAMES
  662. : GPO_USEREXTENSION_NAMES,
  663. TEXT(""),
  664. pszExtensions,
  665. dwSize,
  666. szGPOPath );
  667. }
  668. if ( lstrcmpi( pszExtensions, TEXT("")) == 0 || lstrcmpi( pszExtensions, TEXT(" ")) == 0 ) {
  669. //
  670. // Extensions property was not found
  671. //
  672. LocalFree( pszExtensions );
  673. pszExtensions = 0;
  674. }
  675. }
  676. //
  677. // Tack on the correct subdirectory name
  678. //
  679. DmAssert( lstrlen(szGPOPath) + lstrlen(TEXT("Machine")) + 1 < MAX_PATH );
  680. if (dwFlags & GPO_LIST_FLAG_MACHINE) {
  681. hr = StringCchCopy (lpTemp, MAX_PATH - (lpTemp - szGPOPath), TEXT("Machine"));
  682. } else {
  683. hr = StringCchCopy (lpTemp, MAX_PATH - (lpTemp - szGPOPath), TEXT("User"));
  684. }
  685. if ( FAILED(hr) ) {
  686. xe = HRESULT_CODE(hr);
  687. goto Exit;
  688. }
  689. //
  690. // Add this to the list of paths
  691. //
  692. if ( bRsopLogging ) {
  693. bOk = AddLocalGPO( ppSOMList );
  694. if ( !bOk ) {
  695. xe = GetLastError();
  696. if ( pszExtensions )
  697. LocalFree( pszExtensions );
  698. DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to log Rsop data.")));
  699. goto Exit;
  700. }
  701. bOk = AddGPOToRsopList( ppGpContainerList,
  702. dwFlags,
  703. TRUE,
  704. TRUE,
  705. bDisabled,
  706. dwVersion,
  707. L"LocalGPO",
  708. szGPOPath,
  709. szGPOName,
  710. szGPOName,
  711. 0,
  712. 0,
  713. TRUE,
  714. 0,
  715. L"Local",
  716. 0 );
  717. if ( !bOk ) {
  718. xe = GetLastError();
  719. if ( pszExtensions )
  720. LocalFree( pszExtensions );
  721. DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to log Rsop data.")));
  722. goto Exit;
  723. }
  724. }
  725. if ( !bDisabled && !bOldGpoVersion && !bNoGpoData )
  726. {
  727. bOk = AddGPO (&pGPONonForcedList, dwFlags, TRUE, TRUE, bDisabled, 0, dwVersion,
  728. L"LocalGPO", szGPOPath,
  729. szGPOName, szGPOName, pszExtensions, 0, 0, GPLinkMachine, L"Local", 0, TRUE,
  730. FALSE, bVerbose, TRUE);
  731. }
  732. if ( pszExtensions )
  733. LocalFree( pszExtensions );
  734. if ( bOk ) {
  735. if ( bVerbose ) {
  736. if ( bDisabled || bOldGpoVersion || bNoGpoData ) {
  737. CEvents ev(FALSE, EVENT_NO_LOCAL_GPO);
  738. ev.Report();
  739. }
  740. else {
  741. CEvents ev(FALSE, EVENT_FOUND_LOCAL_GPO);
  742. ev.Report();
  743. }
  744. }
  745. } else {
  746. xe = GetLastError();
  747. DebugMsg((DM_WARNING, TEXT("GetGPOInfo: Failed to add local group policy object to the list.")));
  748. goto Exit;
  749. }
  750. }
  751. //
  752. // Merge the forced and nonforced lists together
  753. //
  754. if (pGPOForcedList && !pGPONonForcedList) {
  755. *lpGPOList = pGPOForcedList;
  756. } else if (!pGPOForcedList && pGPONonForcedList) {
  757. *lpGPOList = pGPONonForcedList;
  758. } else if (pGPOForcedList && pGPONonForcedList) {
  759. lpGPO = pGPONonForcedList;
  760. while (lpGPO->pNext) {
  761. lpGPO = lpGPO->pNext;
  762. }
  763. lpGPO->pNext = pGPOForcedList;
  764. pGPOForcedList->pPrev = lpGPO;
  765. *lpGPOList = pGPONonForcedList;
  766. }
  767. //
  768. // Success
  769. //
  770. bResult = TRUE;
  771. Exit:
  772. //
  773. // Free any GPOs we found
  774. //
  775. if (!bResult) {
  776. FreeGPOList( pGPOForcedList );
  777. FreeGPOList( pGPONonForcedList );
  778. }
  779. //
  780. // Free temporary OU list
  781. //
  782. while ( pDeferredOUList ) {
  783. DNENTRY *pTemp = pDeferredOUList->pNext;
  784. FreeDnEntry( pDeferredOUList );
  785. pDeferredOUList = pTemp;
  786. }
  787. //
  788. // Free temporary deferred GPO lists
  789. //
  790. FreeGPOList( pDeferredForcedList );
  791. FreeGPOList( pDeferredNonForcedList );
  792. if (pld) {
  793. pldap_api->pfnldap_unbind (pld);
  794. }
  795. if ( pldMachine )
  796. {
  797. pldap_api->pfnldap_unbind( pldMachine );
  798. }
  799. DebugMsg((DM_VERBOSE, TEXT("GetGPOInfo: Leaving with %d"), bResult));
  800. DebugMsg((DM_VERBOSE, TEXT("GetGPOInfo: ********************************")));
  801. if ( hToken )
  802. {
  803. CloseHandle( hToken );
  804. }
  805. return bResult;
  806. }
  807. //*************************************************************
  808. //
  809. // GetGPOList()
  810. //
  811. // Purpose: Retreives the list of GPOs for the specified
  812. // user or machine
  813. //
  814. // Parameters: hToken - User or machine token, if NULL,
  815. // lpName and lpDCName must be supplied
  816. // lpName - User or machine name in DN format,
  817. // if hToken is supplied, this must be NULL
  818. // lpHostName - Host name. This should be a domain's
  819. // dn name for best performance. Otherwise
  820. // it can also be a DC name. If hToken is supplied,
  821. // this must be NULL
  822. // lpComputerName - Computer named used to determine site
  823. // information. Can be NULL which means
  824. // use the local machine
  825. // dwFlags - Flags field
  826. // pGPOList - Address of a pointer which receives
  827. // the link list of GPOs
  828. //
  829. // Return: TRUE if successful
  830. // FALSE if an error occurs
  831. //
  832. //*************************************************************
  833. BOOL WINAPI GetGPOList (HANDLE hToken, LPCTSTR lpName, LPCTSTR lpHostName,
  834. LPCTSTR lpComputerName, DWORD dwFlags,
  835. PGROUP_POLICY_OBJECT *pGPOList)
  836. {
  837. PDOMAIN_CONTROLLER_INFO pDCI = NULL;
  838. BOOL bResult = FALSE;
  839. LPTSTR lpDomainDN, lpDNName, lpTemp, lpUserName = NULL;
  840. DWORD dwResult;
  841. HANDLE hOldToken = 0;
  842. PNETAPI32_API pNetAPI32;
  843. LPSCOPEOFMGMT lpSOMList = 0; // LSDOU list
  844. LPGPCONTAINER lpGpContainerList = 0; // GP container list
  845. HRESULT hr;
  846. OLE32_API *pOle32Api = NULL;
  847. XLastError xe;
  848. LPWSTR szSiteName = NULL;
  849. BOOL bInitializedCOM = FALSE;
  850. //
  851. // mask off the flags that are used internally.
  852. //
  853. dwFlags &= FLAG_INTERNAL_MASK;
  854. //
  855. // Verbose output
  856. //
  857. DebugMsg((DM_VERBOSE, TEXT("GetGPOList: Entering.")));
  858. DebugMsg((DM_VERBOSE, TEXT("GetGPOList: hToken = 0x%x"), (hToken ? hToken : 0)));
  859. DebugMsg((DM_VERBOSE, TEXT("GetGPOList: lpName = <%s>"), (lpName ? lpName : TEXT("NULL"))));
  860. DebugMsg((DM_VERBOSE, TEXT("GetGPOList: lpHostName = <%s>"), (lpHostName ? lpHostName : TEXT("NULL"))));
  861. DebugMsg((DM_VERBOSE, TEXT("GetGPOList: dwFlags = 0x%x"), dwFlags));
  862. //
  863. // Check parameters
  864. //
  865. if (hToken) {
  866. if (lpName || lpHostName) {
  867. xe = ERROR_INVALID_PARAMETER;
  868. DebugMsg((DM_WARNING, TEXT("GetGPOList: lpName and lpHostName must be NULL")));
  869. SetLastError(ERROR_INVALID_PARAMETER);
  870. return FALSE;
  871. }
  872. } else {
  873. if (!lpName || !lpHostName) {
  874. xe = ERROR_INVALID_PARAMETER;
  875. DebugMsg((DM_WARNING, TEXT("GetGPOList: lpName and lpHostName must be valid")));
  876. SetLastError(ERROR_INVALID_PARAMETER);
  877. return FALSE;
  878. }
  879. }
  880. // check if there is space in the lpHostName
  881. if (lpHostName)
  882. {
  883. // fixing bug 567835
  884. // check if there is space in the lpHostName
  885. LPCTSTR lpPtr = lpHostName;
  886. while (*lpPtr) {
  887. if (*lpPtr == L' ')
  888. {
  889. xe = ERROR_INVALID_PARAMETER;
  890. DebugMsg((DM_WARNING, TEXT("GetGPOInfo: lpHostName shld not contain space in it")));
  891. return FALSE;
  892. }
  893. lpPtr++;
  894. }
  895. }
  896. if (!pGPOList) {
  897. xe = ERROR_INVALID_PARAMETER;
  898. DebugMsg((DM_WARNING, TEXT("GetGPOList: pGPOList is null")));
  899. SetLastError(ERROR_INVALID_PARAMETER);
  900. return FALSE;
  901. }
  902. //
  903. // Load netapi32
  904. //
  905. pNetAPI32 = LoadNetAPI32();
  906. if (!pNetAPI32) {
  907. xe = GetLastError();
  908. DebugMsg((DM_WARNING, TEXT("GetGPOList: Failed to load netapi32 with %d."),
  909. GetLastError()));
  910. goto Exit;
  911. }
  912. //
  913. // If an hToken was offered, then we need to get the name and
  914. // domain DN name
  915. //
  916. if (hToken) {
  917. //
  918. // Impersonate the user / machine
  919. //
  920. if (!ImpersonateUser(hToken, &hOldToken)) {
  921. xe = GetLastError();
  922. DebugMsg((DM_WARNING, TEXT("GetGPOList: Failed to impersonate user")));
  923. return FALSE;
  924. }
  925. //
  926. // Get the username in DN format
  927. //
  928. lpUserName = MyGetUserName (NameFullyQualifiedDN);
  929. if (!lpUserName) {
  930. xe = GetLastError();
  931. DebugMsg((DM_WARNING, TEXT("GetGPOList: MyGetUserName failed for DN style name with %d"),
  932. GetLastError()));
  933. CEvents ev(TRUE, EVENT_FAILED_USERNAME);
  934. ev.AddArgWin32Error(GetLastError()); ev.Report();
  935. goto Exit;
  936. }
  937. lpDNName = lpUserName;
  938. DebugMsg((DM_VERBOSE, TEXT("GetGPOList: Queried lpDNName = <%s>"), lpDNName));
  939. //
  940. // Get the dns domain name
  941. //
  942. lpDomainDN = MyGetDomainDNSName ();
  943. if (!lpDomainDN) {
  944. xe = GetLastError();
  945. DebugMsg((DM_WARNING, TEXT("GetGPOList: MyGetUserName failed for dns domain name with %d"),
  946. GetLastError()));
  947. CEvents ev(TRUE, EVENT_FAILED_USERNAME);
  948. ev.AddArgWin32Error(GetLastError()); ev.Report();
  949. goto Exit;
  950. }
  951. //
  952. // Check this domain for a DC
  953. //
  954. dwResult = pNetAPI32->pfnDsGetDcName (NULL, lpDomainDN, NULL, NULL,
  955. DS_DIRECTORY_SERVICE_PREFERRED |
  956. DS_RETURN_DNS_NAME,
  957. &pDCI);
  958. if (dwResult != ERROR_SUCCESS) {
  959. xe = dwResult;
  960. DebugMsg((DM_WARNING, TEXT("GetGPOList: DSGetDCName failed with %d for <%s>"),
  961. dwResult, lpDomainDN));
  962. goto Exit;
  963. }
  964. //
  965. // Found a DC, does it have a DS ?
  966. //
  967. if (!(pDCI->Flags & DS_DS_FLAG)) {
  968. xe = ERROR_DS_DS_REQUIRED;
  969. pNetAPI32->pfnNetApiBufferFree(pDCI);
  970. DebugMsg((DM_WARNING, TEXT("GetGPOList: The domain <%s> does not have a DS"),
  971. lpDomainDN));
  972. goto Exit;
  973. }
  974. pNetAPI32->pfnNetApiBufferFree(pDCI);
  975. } else {
  976. //
  977. // Use the server and DN name passed in
  978. //
  979. lpDomainDN = (LPTSTR)lpHostName;
  980. lpDNName = (LPTSTR)lpName;
  981. }
  982. pOle32Api = LoadOle32Api();
  983. if ( pOle32Api == NULL ) {
  984. xe = GetLastError();
  985. DebugMsg((DM_WARNING, TEXT("GetGPOList: Failed to load ole32.dll.") ));
  986. goto Exit;
  987. }
  988. hr = pOle32Api->pfnCoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
  989. if ( SUCCEEDED(hr) )
  990. {
  991. bInitializedCOM = TRUE;
  992. }
  993. //
  994. // If this thread is already initialized, this is fine -- we will ignore
  995. // this since we are safely initialized, we just need to remember not
  996. // to try to uninitialize the thread later
  997. //
  998. if ( RPC_E_CHANGED_MODE == hr )
  999. {
  1000. hr = S_OK;
  1001. }
  1002. if ( FAILED(hr) ) {
  1003. xe = HRESULT_CODE(hr);
  1004. DebugMsg((DM_WARNING, TEXT("GetGPOList: CoInitializeEx failed with 0x%x."), hr ));
  1005. goto Exit;
  1006. }
  1007. hr = CoInitializeSecurity(NULL, -1, NULL, NULL,
  1008. RPC_C_AUTHN_LEVEL_DEFAULT, /* this should be the current value */
  1009. RPC_C_IMP_LEVEL_IMPERSONATE,
  1010. NULL, EOAC_NONE, NULL);
  1011. if ( FAILED(hr) ) {
  1012. DebugMsg((DM_WARNING, TEXT("GetGPOList: CoInitializeSecurity failed with 0x%x"), hr ));
  1013. }
  1014. //
  1015. // Call to get the list of GPOs
  1016. //
  1017. dwResult = pNetAPI32->pfnDsGetSiteName(lpComputerName, &szSiteName);
  1018. if ( dwResult != ERROR_SUCCESS )
  1019. {
  1020. if ( dwResult != ERROR_NO_SITENAME )
  1021. {
  1022. xe = dwResult;
  1023. DebugMsg((DM_WARNING, TEXT("GetGPOList: DSGetSiteName failed, exiting. 0x%x"), dwResult ));
  1024. goto Exit;
  1025. }
  1026. szSiteName = 0;
  1027. }
  1028. {
  1029. CLocator locator;
  1030. // Clocator has a bunch of OLE interfaces.
  1031. // It should be released before CoUninit gets called
  1032. bResult = GetGPOInfo( dwFlags,
  1033. lpDomainDN,
  1034. lpDNName,
  1035. lpComputerName,
  1036. pGPOList,
  1037. &lpSOMList,
  1038. &lpGpContainerList,
  1039. pNetAPI32,
  1040. FALSE,
  1041. 0,
  1042. szSiteName,
  1043. 0,
  1044. &locator );
  1045. if (!bResult) {
  1046. xe = GetLastError();
  1047. }
  1048. }
  1049. Exit:
  1050. if ( bInitializedCOM )
  1051. {
  1052. pOle32Api->pfnCoUnInitialize();
  1053. }
  1054. //
  1055. // Stop impersonating if a hToken was given
  1056. //
  1057. if ( hOldToken ) {
  1058. RevertToUser(&hOldToken);
  1059. }
  1060. if (lpDomainDN) {
  1061. LocalFree (lpDomainDN);
  1062. }
  1063. if (lpUserName) {
  1064. LocalFree (lpUserName);
  1065. }
  1066. if ( szSiteName )
  1067. {
  1068. pNetAPI32->pfnNetApiBufferFree( szSiteName );
  1069. }
  1070. FreeSOMList( lpSOMList );
  1071. FreeGpContainerList( lpGpContainerList );
  1072. DebugMsg((DM_VERBOSE, TEXT("GetGPOList: Leaving with %d"), bResult));
  1073. return bResult;
  1074. }