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

3567 lines
113 KiB

  1. //*************************************************************
  2. //
  3. // Group Policy Support - Queries about the Policies
  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. // AddGPO()
  15. //
  16. // Purpose: Adds a GPO to the list
  17. //
  18. // Parameters: lpGPOList - list of GPOs
  19. // dwFlags - Flags
  20. // bFound - Was Gpo found ?
  21. // bAccessGranted - Was access granted ?
  22. // bDisabled - Is this Gpo disabled ?
  23. // dwOptions - Options
  24. // dwVersion - Version number
  25. // lpDSPath - DS path
  26. // lpFileSysPath - File system path
  27. // lpDisplayName - Friendly display name
  28. // lpGPOName - GPO name
  29. // lpExtensions - Extensions relevant to this GPO
  30. // lpDSObject - LSDOU
  31. // pSD - Ptr to security descriptor
  32. // cbSDLen - Length of security descriptor in bytes
  33. // GPOLink - GPO link type
  34. // lpLink - SDOU this GPO is linked to
  35. // lParam - lParam
  36. // bFront - Head or end of list
  37. // bBlock - Block from above flag
  38. // bVerbose - Verbose output flag
  39. //
  40. //
  41. // Return: TRUE if successful
  42. // FALSE if an error occurs
  43. //
  44. //*************************************************************
  45. BOOL AddGPO (PGROUP_POLICY_OBJECT * lpGPOList,
  46. DWORD dwFlags, BOOL bFound, BOOL bAccessGranted, BOOL bDisabled, DWORD dwOptions,
  47. DWORD dwVersion, LPTSTR lpDSPath, LPTSTR lpFileSysPath,
  48. LPTSTR lpDisplayName, LPTSTR lpGPOName, LPTSTR lpExtensions,
  49. PSECURITY_DESCRIPTOR pSD, DWORD cbSDLen,
  50. GPO_LINK GPOLink, LPTSTR lpLink,
  51. LPARAM lParam, BOOL bFront, BOOL bBlock, BOOL bVerbose, BOOL bProcessGPO)
  52. {
  53. PGROUP_POLICY_OBJECT lpNew, lpTemp;
  54. DWORD dwSize;
  55. XLastError xe;
  56. HRESULT hr = S_OK;
  57. //
  58. // Check if this item should be excluded from the list
  59. //
  60. if (bBlock) {
  61. if (!(dwOptions & GPO_FLAG_FORCE)) {
  62. DebugMsg((DM_VERBOSE, TEXT("AddGPO: GPO %s will not be added to the list since the Block flag is set and this GPO is not in enforce mode."),
  63. lpDisplayName));
  64. if (bVerbose) {
  65. CEvents ev(FALSE, EVENT_SKIP_GPO);
  66. ev.AddArg(lpDisplayName); ev.Report();
  67. }
  68. if (dwFlags & GP_PLANMODE) {
  69. DebugMsg((DM_VERBOSE, TEXT("AddGPO: GPO %s will will still be queried for since this is planning mode."),
  70. lpDisplayName));
  71. bProcessGPO = FALSE;
  72. }
  73. else
  74. return TRUE;
  75. }
  76. }
  77. //
  78. // Calculate the size of the new GPO item
  79. //
  80. dwSize = sizeof (GROUP_POLICY_OBJECT);
  81. if (lpDSPath) {
  82. dwSize += ((lstrlen(lpDSPath) + 1) * sizeof(TCHAR));
  83. }
  84. if (lpFileSysPath) {
  85. dwSize += ((lstrlen(lpFileSysPath) + 1) * sizeof(TCHAR));
  86. }
  87. if (lpDisplayName) {
  88. dwSize += ((lstrlen(lpDisplayName) + 1) * sizeof(TCHAR));
  89. }
  90. if (lpExtensions) {
  91. dwSize += ((lstrlen(lpExtensions) + 1) * sizeof(TCHAR));
  92. }
  93. if (lpLink) {
  94. dwSize += ((lstrlen(lpLink) + 1) * sizeof(TCHAR));
  95. }
  96. dwSize += sizeof(GPOPROCDATA);
  97. //
  98. // Allocate space for it
  99. //
  100. lpNew = (PGROUP_POLICY_OBJECT) LocalAlloc (LPTR, dwSize);
  101. if (!lpNew) {
  102. DebugMsg((DM_WARNING, TEXT("AddGPO: Failed to allocate memory with %d"),
  103. GetLastError()));
  104. return FALSE;
  105. }
  106. //
  107. // Fill in item
  108. //
  109. LPGPOPROCDATA lpGpoProcData;
  110. lpNew->lParam2 = (LPARAM)(((LPBYTE)lpNew) + sizeof(GROUP_POLICY_OBJECT));
  111. lpGpoProcData = (LPGPOPROCDATA)lpNew->lParam2;
  112. lpGpoProcData->bProcessGPO = bProcessGPO;
  113. lpNew->dwOptions = dwOptions;
  114. lpNew->dwVersion = dwVersion;
  115. if (lpDSPath) {
  116. lpNew->lpDSPath = (LPTSTR)(((LPBYTE)lpNew) + sizeof(GROUP_POLICY_OBJECT) + sizeof(GPOPROCDATA));
  117. hr = StringCchCopy (lpNew->lpDSPath, lstrlen(lpDSPath) + 1, lpDSPath);
  118. ASSERT(SUCCEEDED(hr));
  119. }
  120. if (lpFileSysPath) {
  121. if (lpDSPath) {
  122. lpNew->lpFileSysPath = lpNew->lpDSPath + lstrlen (lpNew->lpDSPath) + 1;
  123. } else {
  124. lpNew->lpFileSysPath = (LPTSTR)(((LPBYTE)lpNew) + sizeof(GROUP_POLICY_OBJECT) + sizeof(GPOPROCDATA));
  125. }
  126. hr = StringCchCopy (lpNew->lpFileSysPath, lstrlen(lpFileSysPath) + 1, lpFileSysPath);
  127. ASSERT(SUCCEEDED(hr));
  128. }
  129. if (lpDisplayName) {
  130. if (lpFileSysPath) {
  131. lpNew->lpDisplayName = lpNew->lpFileSysPath + lstrlen (lpNew->lpFileSysPath) + 1;
  132. } else {
  133. if (lpDSPath)
  134. {
  135. lpNew->lpDisplayName = lpNew->lpDSPath + lstrlen (lpNew->lpDSPath) + 1;
  136. }
  137. else
  138. {
  139. lpNew->lpDisplayName = (LPTSTR)(((LPBYTE)lpNew) + sizeof(GROUP_POLICY_OBJECT) + sizeof(GPOPROCDATA));
  140. }
  141. }
  142. hr = StringCchCopy (lpNew->lpDisplayName, lstrlen(lpDisplayName) + 1, lpDisplayName);
  143. ASSERT(SUCCEEDED(hr));
  144. }
  145. if (lpGPOName) {
  146. DmAssert( lstrlen(lpGPOName) < 50 );
  147. hr = StringCchCopy (lpNew->szGPOName, 50, lpGPOName);
  148. ASSERT(SUCCEEDED(hr));
  149. }
  150. if (lpExtensions) {
  151. if (lpDisplayName) {
  152. lpNew->lpExtensions = lpNew->lpDisplayName + lstrlen(lpNew->lpDisplayName) + 1;
  153. } else {
  154. if (lpFileSysPath) {
  155. lpNew->lpExtensions = lpNew->lpFileSysPath + lstrlen(lpNew->lpFileSysPath) + 1;
  156. } else {
  157. if (lpDSPath) {
  158. lpNew->lpExtensions = lpNew->lpDSPath + lstrlen(lpNew->lpDSPath) + 1;
  159. } else {
  160. lpNew->lpExtensions = (LPTSTR)(((LPBYTE)lpNew) + sizeof(GROUP_POLICY_OBJECT) + sizeof(GPOPROCDATA));
  161. }
  162. }
  163. }
  164. hr = StringCchCopy (lpNew->lpExtensions, lstrlen(lpExtensions) + 1, lpExtensions);
  165. ASSERT(SUCCEEDED(hr));
  166. }
  167. if (lpLink) {
  168. if (lpExtensions) {
  169. lpNew->lpLink = lpNew->lpExtensions + lstrlen(lpNew->lpExtensions) + 1;
  170. } else {
  171. if (lpDisplayName) {
  172. lpNew->lpLink = lpNew->lpDisplayName + lstrlen(lpNew->lpDisplayName) + 1;
  173. } else {
  174. if (lpFileSysPath) {
  175. lpNew->lpLink = lpNew->lpFileSysPath + lstrlen(lpNew->lpFileSysPath) + 1;
  176. } else {
  177. if (lpDSPath) {
  178. lpNew->lpLink = lpNew->lpDSPath + lstrlen(lpNew->lpDSPath) + 1;
  179. } else {
  180. lpNew->lpLink = (LPTSTR)(((LPBYTE)lpNew) + sizeof(GROUP_POLICY_OBJECT) + sizeof(GPOPROCDATA));
  181. }
  182. }
  183. }
  184. }
  185. hr = StringCchCopy (lpNew->lpLink, lstrlen(lpLink) + 1, lpLink);
  186. ASSERT(SUCCEEDED(hr));
  187. }
  188. lpNew->GPOLink = GPOLink;
  189. lpNew->lParam = lParam;
  190. //
  191. // Add item to link list
  192. //
  193. if (*lpGPOList) {
  194. if (bFront) {
  195. (*lpGPOList)->pPrev = lpNew;
  196. lpNew->pNext = *lpGPOList;
  197. *lpGPOList = lpNew;
  198. } else {
  199. lpTemp = *lpGPOList;
  200. while (lpTemp->pNext != NULL) {
  201. lpTemp = lpTemp->pNext;
  202. }
  203. lpTemp->pNext = lpNew;
  204. lpNew->pPrev = lpTemp;
  205. }
  206. } else {
  207. //
  208. // First item in the list
  209. //
  210. *lpGPOList = lpNew;
  211. }
  212. return TRUE;
  213. }
  214. //*************************************************************
  215. //
  216. // AddGPOToRsopList
  217. //
  218. // Purpose: Adds GPO to list of GPOs being logged by Rsop
  219. //
  220. // Parameters: ppGpContainerList - List of Gp Containers
  221. // dwFlags - Flags
  222. // bFound - Was Gpo found ?
  223. // bAccessGranted - Was access granted ?
  224. // bDisabled - Is this Gpo disabled ?
  225. // dwOptions - Options
  226. // dwVersion - Version number
  227. // lpDSPath - DS path
  228. // lpFileSysPath - File system path
  229. // lpDisplayName - Friendly display name
  230. // lpGPOName - GPO name
  231. // pSD - Pointer to security descriptor
  232. // cbSDLen - Length of security descriptor in bytes
  233. // bFilterAllowed - Does GPO pass filter check
  234. // pwszFilterId - WQL filter id
  235. // szSOM - SOM
  236. // dwGPOOptions - GPO options
  237. //
  238. //*************************************************************
  239. BOOL AddGPOToRsopList( LPGPCONTAINER *ppGpContainerList,
  240. DWORD dwFlags,
  241. BOOL bFound,
  242. BOOL bAccessGranted,
  243. BOOL bDisabled,
  244. DWORD dwVersion,
  245. LPTSTR lpDSPath,
  246. LPTSTR lpFileSysPath,
  247. LPTSTR lpDisplayName,
  248. LPTSTR lpGPOName,
  249. PSECURITY_DESCRIPTOR pSD,
  250. DWORD cbSDLen,
  251. BOOL bFilterAllowed,
  252. WCHAR *pwszFilterId,
  253. LPWSTR szSOM,
  254. DWORD dwOptions)
  255. {
  256. // Fixing bug 568213
  257. XLastError xe;
  258. GPCONTAINER *pGpContainer = AllocGpContainer( dwFlags,
  259. bFound,
  260. bAccessGranted,
  261. bDisabled,
  262. dwVersion,
  263. lpDSPath,
  264. lpFileSysPath,
  265. lpDisplayName,
  266. lpGPOName,
  267. pSD,
  268. cbSDLen,
  269. bFilterAllowed,
  270. pwszFilterId,
  271. szSOM,
  272. dwOptions );
  273. if ( pGpContainer == NULL ) {
  274. DebugMsg((DM_VERBOSE, TEXT("AddGPO: Failed to allocate memory for Gp Container.")));
  275. return FALSE;
  276. }
  277. //
  278. // Prepend to GpContainer list
  279. //
  280. pGpContainer->pNext = *ppGpContainerList;
  281. *ppGpContainerList = pGpContainer;
  282. return TRUE;
  283. }
  284. //*************************************************************
  285. //
  286. // AddLocalGPO()
  287. //
  288. // Purpose: Adds a local Gpo to the list of SOMs
  289. //
  290. // Parameters: ppSOMList - List of SOMs
  291. //
  292. //*************************************************************
  293. BOOL AddLocalGPO( LPSCOPEOFMGMT *ppSOMList )
  294. {
  295. GPLINK *pGpLink = NULL;
  296. XLastError xe;
  297. SCOPEOFMGMT *pSOM = AllocSOM( L"Local" );
  298. if ( pSOM == NULL ) {
  299. DebugMsg((DM_WARNING, TEXT("AddLocalGPO: Unable to allocate memory for SOM object")));
  300. return FALSE;
  301. }
  302. pSOM->dwType = GPLinkMachine;
  303. // Local GPO cannot be blocked from above
  304. pGpLink = AllocGpLink( L"LocalGPO", 0 );
  305. if ( pGpLink == NULL ) {
  306. xe = GetLastError();
  307. DebugMsg((DM_WARNING, TEXT("AddLocalGPO: Unable to allocate memory for GpLink object")));
  308. FreeSOM( pSOM );
  309. return FALSE;
  310. }
  311. pSOM->pGpLinkList = pGpLink;
  312. pSOM->pNext = *ppSOMList;
  313. *ppSOMList = pSOM;
  314. return TRUE;
  315. }
  316. //*************************************************************
  317. //
  318. // ProcessGPO()
  319. //
  320. // Purpose: Processes a specific GPO
  321. //
  322. // Parameters: lpGPOPath - Path to the GPO
  323. // lpDSPath - DS object
  324. // dwFlags - GetGPOList flags
  325. // HANDLE - user or machine aceess token
  326. // lpGPOList - List of GPOs
  327. // ppGpContainerList - List of Gp containers
  328. // dwGPOOptions - Link options
  329. // bDeferred - Should ldap query be deferred ?
  330. // bVerbose - Verbose output
  331. // GPOLink - GPO link type
  332. // lpDSObject - SDOU this gpo is linked to
  333. // pld - LDAP info
  334. // pLDAP - LDAP api
  335. // pLdapMsg - LDAP message
  336. // bBlock - Block flag
  337. // bRsopToken - Rsop security token
  338. // pGpoFilter - Gpo filter
  339. // pLocator - WMI interface class
  340. // bAddGPO - In planning mode we want to get the gpodata even if
  341. // the GPO is not going to be applied
  342. //
  343. //
  344. // Return: TRUE if successful
  345. // FALSE if an error occurs
  346. //
  347. //*************************************************************
  348. BOOL ProcessGPO(LPTSTR lpGPOPath,
  349. DWORD dwFlags,
  350. HANDLE hToken,
  351. PGROUP_POLICY_OBJECT *lpGPOList,
  352. LPGPCONTAINER *ppGpContainerList,
  353. DWORD dwGPOOptions,
  354. BOOL bDeferred,
  355. BOOL bVerbose,
  356. GPO_LINK GPOLink,
  357. LPTSTR lpDSObject,
  358. PLDAP pld,
  359. PLDAP_API pLDAP,
  360. PLDAPMessage pMessage,
  361. BOOL bBlock,
  362. PRSOPTOKEN pRsopToken,
  363. CGpoFilter *pGpoFilter,
  364. CLocator *pLocator,
  365. BOOL bProcessGPO )
  366. {
  367. ULONG ulResult, i;
  368. BOOL bResult = FALSE;
  369. BOOL bFound = FALSE;
  370. BOOL bOwnLdapMsg = FALSE; // LDAP message owned by us (if true) or caller (if false)
  371. BOOL bAccessGranted;
  372. DWORD dwFunctionalityVersion = 2;
  373. DWORD dwVersion = 0;
  374. DWORD dwGPOFlags = 0;
  375. DWORD dwGPTVersion = 0;
  376. TCHAR szGPOName[80];
  377. TCHAR *pszGPTPath = 0;
  378. TCHAR *pszFriendlyName = 0;
  379. LPTSTR lpPath, lpEnd, lpTemp;
  380. TCHAR *pszExtensions = 0;
  381. TCHAR szLDAP[] = TEXT("LDAP://");
  382. INT iStrLen = lstrlen(szLDAP);
  383. BYTE berValue[8];
  384. LDAPControl SeInfoControl = { LDAP_SERVER_SD_FLAGS_OID_W, { 5, (PCHAR)berValue }, TRUE };
  385. LDAPControl referralControl = { LDAP_SERVER_DOMAIN_SCOPE_OID_W, { 0, NULL}, TRUE };
  386. PLDAPControl ServerControls[] = { &SeInfoControl, &referralControl, NULL };
  387. TCHAR szSDProperty[] = TEXT("nTSecurityDescriptor");
  388. TCHAR szCommonName[] = TEXT("cn");
  389. TCHAR szDisplayName[] = TEXT("displayName");
  390. TCHAR szFileSysPath[] = TEXT("gPCFileSysPath");
  391. TCHAR szVersion[] = TEXT("versionNumber");
  392. TCHAR szFunctionalityVersion[] = GPO_FUNCTIONALITY_VERSION;
  393. TCHAR szFlags[] = TEXT("flags");
  394. TCHAR szWmiFilter[] = TEXT("gPCWQLFilter");
  395. PWSTR rgAttribs[12] = {szSDProperty,
  396. szFileSysPath,
  397. szCommonName,
  398. szDisplayName,
  399. szVersion,
  400. szFunctionalityVersion,
  401. szFlags,
  402. GPO_MACHEXTENSION_NAMES,
  403. GPO_USEREXTENSION_NAMES,
  404. szObjectClass,
  405. szWmiFilter,
  406. NULL };
  407. LPTSTR *lpValues;
  408. PSECURITY_DESCRIPTOR pSD = NULL; // Security Descriptor
  409. DWORD cbSDLen = 0; // Length of security descriptor in bytes
  410. BOOL bRsopLogging = (ppGpContainerList != NULL);
  411. BOOL bOldGpoVersion = FALSE;
  412. BOOL bDisabled = FALSE;
  413. BOOL bNoGpoData = FALSE;
  414. BOOL bFilterAllowed = FALSE;
  415. WCHAR *pwszFilterId = NULL;
  416. XLastError xe;
  417. HRESULT hr = S_OK;
  418. //
  419. // Verbose output
  420. //
  421. DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: ==============================")));
  422. //
  423. // Skip the starting LDAP provider if found
  424. //
  425. if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE,
  426. lpGPOPath, iStrLen, szLDAP, iStrLen) == CSTR_EQUAL)
  427. {
  428. lpPath = lpGPOPath + iStrLen;
  429. }
  430. else
  431. {
  432. lpPath = lpGPOPath;
  433. }
  434. if ( bDeferred )
  435. {
  436. bResult = AddGPO (lpGPOList, dwFlags, TRUE, TRUE, FALSE, dwGPOOptions, 0, lpPath,
  437. 0, 0, 0, 0, 0, 0, GPOLink, lpDSObject, 0,
  438. FALSE, bBlock, bVerbose, bProcessGPO);
  439. if (!bResult)
  440. DebugMsg((DM_WARNING, TEXT("ProcessGPO: Failed to add GPO <%s> to the list."), lpPath));
  441. DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: Deferring search for <%s>"), lpGPOPath));
  442. return bResult;
  443. }
  444. DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: Searching <%s>"), lpGPOPath));
  445. //
  446. // Check if this user or machine has access to the GPO, and if so,
  447. // should that GPO be applied to them.
  448. //
  449. if (!CheckGPOAccess (pld, pLDAP, hToken, pMessage, szSDProperty, dwFlags, &pSD, &cbSDLen, &bAccessGranted, pRsopToken)) {
  450. xe = GetLastError();
  451. DebugMsg((DM_WARNING, TEXT("ProcessGPO: CheckGPOAccess failed for <%s>"), lpGPOPath));
  452. CEvents ev(TRUE, EVENT_FAILED_ACCESS_CHECK);
  453. ev.AddArg(lpGPOPath); ev.AddArgWin32Error(GetLastError()); ev.Report();
  454. goto Exit;
  455. }
  456. if (!bAccessGranted) {
  457. if (dwFlags & GPO_LIST_FLAG_MACHINE) {
  458. DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: Machine does not have access to the GPO and so will not be applied.")));
  459. } else {
  460. DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: User does not have access to the GPO and so will not be applied.")));
  461. }
  462. if (bVerbose) {
  463. CEvents ev(FALSE, EVENT_NO_ACCESS);
  464. ev.AddArg(lpGPOPath); ev.Report();
  465. }
  466. bResult = TRUE; // GPO is not getting applied
  467. if ( !bRsopLogging ) {
  468. goto Exit;
  469. }
  470. } else {
  471. if (dwFlags & GPO_LIST_FLAG_MACHINE) {
  472. DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: Machine has access to this GPO.")));
  473. } else {
  474. DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: User has access to this GPO.")));
  475. }
  476. }
  477. // only if access is granted will we eval WQL filters
  478. if ( bAccessGranted ) {
  479. if (!FilterCheck(pld, pLDAP, pMessage, pRsopToken, szWmiFilter, pGpoFilter, pLocator, &bFilterAllowed, &pwszFilterId ) ) {
  480. xe = GetLastError();
  481. if (xe == WBEM_E_NOT_FOUND) {
  482. DebugMsg((DM_WARNING, TEXT("ProcessGPO: CheckFilterAcess failed for <%s>. Filter not found"), lpGPOPath));
  483. CEvents ev(TRUE, EVENT_WMIFILTER_NOTFOUND);
  484. ev.AddArg(lpGPOPath); ev.Report();
  485. bFilterAllowed = FALSE;
  486. }
  487. else if (xe == HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED)) {
  488. DebugMsg((DM_WARNING, TEXT("ProcessGPO: CheckFilterAcess failed for <%s>. WMI service is disabled"), lpGPOPath));
  489. CEvents ev(TRUE, EVENT_WMISERVICE_DISABLED);
  490. ev.AddArg(lpGPOPath); ev.Report();
  491. bFilterAllowed = FALSE;
  492. }
  493. else {
  494. DebugMsg((DM_WARNING, TEXT("ProcessGPO: CheckFilterAcess failed for <%s>"), lpGPOPath));
  495. CEvents ev(TRUE, EVENT_FAILED_FILTER_CHECK);
  496. ev.AddArg(lpGPOPath); ev.Report();
  497. goto Exit;
  498. }
  499. }
  500. if ( (dwFlags & GP_PLANMODE) && (dwFlags & GPO_LIST_FLAG_MACHINE) && (dwFlags & FLAG_ASSUME_COMP_WQLFILTER_TRUE) ) {
  501. bFilterAllowed = TRUE;
  502. DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: Machine WQL filter is assumed to be true.")));
  503. }
  504. else if ( (dwFlags & GP_PLANMODE) && ((dwFlags & GPO_LIST_FLAG_MACHINE) == 0) && (dwFlags & FLAG_ASSUME_USER_WQLFILTER_TRUE) ) {
  505. bFilterAllowed = TRUE;
  506. DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: User WQL filter is assumed to be true.")));
  507. }
  508. if (!bFilterAllowed)
  509. {
  510. DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: The GPO does not pass the filter check and so will not be applied.")));
  511. if (bVerbose) {
  512. CEvents ev(FALSE, EVENT_NO_FILTER_ALLOWED);
  513. ev.AddArg(lpGPOPath); ev.Report();
  514. }
  515. bResult = TRUE; // GPO is not getting applied
  516. if ( !bRsopLogging ) {
  517. goto Exit;
  518. }
  519. } else {
  520. DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: GPO passes the filter check.")));
  521. }
  522. }
  523. else {
  524. bFilterAllowed = FALSE;
  525. }
  526. //
  527. // Either user has access to this GPO, or Rsop logging is enabled so retrieve remaining GPO attributes
  528. //
  529. //
  530. // Check if this object is a GPO
  531. //
  532. lpValues = pLDAP->pfnldap_get_values(pld, pMessage, szObjectClass);
  533. if (lpValues) {
  534. bFound = FALSE;
  535. for ( i=0; lpValues[i] != NULL; i++) {
  536. if ( lstrcmp( lpValues[i], szDSClassGPO ) == 0 ) {
  537. bFound = TRUE;
  538. break;
  539. }
  540. }
  541. pLDAP->pfnldap_value_free (lpValues);
  542. if ( !bFound ) {
  543. xe = ERROR_DS_MISSING_REQUIRED_ATT;
  544. // seems like objectclass=dsgpo is required attr
  545. DebugMsg((DM_WARNING, TEXT("ProcessGPO: Object <%s> is not a GPO"), lpGPOPath ));
  546. CEvents ev(TRUE, EVENT_INCORRECT_CLASS);
  547. ev.AddArg(lpGPOPath); ev.AddArg(szDSClassGPO); ev.Report();
  548. goto Exit;
  549. }
  550. }
  551. //
  552. // In the results, get the values that match the gPCFunctionalityVersion attribute
  553. //
  554. lpValues = pLDAP->pfnldap_get_values(pld, pMessage, szFunctionalityVersion);
  555. if (lpValues) {
  556. dwFunctionalityVersion = StringToInt (*lpValues);
  557. DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: Found functionality version of: %d"),
  558. dwFunctionalityVersion));
  559. pLDAP->pfnldap_value_free (lpValues);
  560. } else {
  561. ulResult = pLDAP->pfnLdapGetLastError();
  562. if (ulResult == LDAP_NO_SUCH_ATTRIBUTE) {
  563. if (dwFlags & GPO_LIST_FLAG_MACHINE) {
  564. DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: Machine does not have access to <%s>"), lpGPOPath));
  565. } else {
  566. DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: User does not have access to <%s>"), lpGPOPath));
  567. }
  568. if (bVerbose) {
  569. CEvents ev(FALSE, EVENT_NO_ACCESS);
  570. ev.AddArg(lpGPOPath); ev.Report();
  571. }
  572. bResult = TRUE;
  573. } else {
  574. xe = pLDAP->pfnLdapMapErrorToWin32(ulResult);
  575. DebugMsg((DM_WARNING, TEXT("ProcessGPO: GPO %s does not have a functionality version number, error = 0x%x."), lpGPOPath, ulResult));
  576. CEvents ev(TRUE, EVENT_CORRUPT_GPO_FUNCVERSION);
  577. ev.AddArg(lpGPOPath); ev.Report();
  578. }
  579. goto Exit;
  580. }
  581. //
  582. // In the results, get the values that match the gPCFileSystemPath attribute
  583. //
  584. lpValues = pLDAP->pfnldap_get_values (pld, pMessage, szFileSysPath);
  585. if (lpValues) {
  586. // Fixing bug 568261
  587. DWORD dwGPTPathLength = lstrlen(*lpValues) + MAX(lstrlen(TEXT("\\Machine")), lstrlen(TEXT("\\gpt.ini"))) + 1; //Take the MAX of MACHINE and gpt.ini
  588. pszGPTPath = (LPWSTR) LocalAlloc( LPTR, (dwGPTPathLength) * sizeof(TCHAR) );
  589. if ( pszGPTPath == 0) {
  590. xe = GetLastError();
  591. DebugMsg((DM_WARNING, TEXT("ProcessGPO: Unable to allocate memory")));
  592. pLDAP->pfnldap_value_free (lpValues);
  593. goto Exit;
  594. }
  595. hr = StringCchCopy (pszGPTPath, dwGPTPathLength, *lpValues);
  596. ASSERT(SUCCEEDED(hr));
  597. DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: Found file system path of: <%s>"), pszGPTPath));
  598. pLDAP->pfnldap_value_free (lpValues);
  599. lpEnd = CheckSlash (pszGPTPath);
  600. //
  601. // Get the GPT version number
  602. //
  603. hr = StringCchCopy (lpEnd, dwGPTPathLength - (lpEnd - pszGPTPath), TEXT("gpt.ini"));
  604. ASSERT(SUCCEEDED(hr));
  605. //
  606. // Skip access to sysvol if AGP or filtercheck fails
  607. //
  608. if (bAccessGranted && bFilterAllowed) {
  609. WIN32_FILE_ATTRIBUTE_DATA fad;
  610. //
  611. // Check for the existence of the gpt.ini file.
  612. //
  613. if (GetFileAttributesEx(pszGPTPath, GetFileExInfoStandard, &fad)) {
  614. dwGPTVersion = GetPrivateProfileInt(TEXT("General"), TEXT("Version"), 0, pszGPTPath);
  615. }
  616. else {
  617. xe = GetLastError();
  618. DebugMsg((DM_WARNING, TEXT("ProcessGPO: Couldn't find the group policy template file <%s>, error = 0x%x."), pszGPTPath, GetLastError()));
  619. CEvents ev(TRUE, EVENT_GPT_NOTACCESSIBLE);
  620. ev.AddArg(lpGPOPath); ev.AddArg(pszGPTPath); ev.AddArgWin32Error(GetLastError()); ev.Report();
  621. goto Exit;
  622. }
  623. }
  624. else {
  625. DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: Sysvol access skipped because GPO is not getting applied.")));
  626. dwGPTVersion = 0xffffffff;
  627. }
  628. if (dwFlags & GPO_LIST_FLAG_MACHINE) {
  629. hr = StringCchCopy (lpEnd, dwGPTPathLength - (lpEnd - pszGPTPath), TEXT("Machine"));
  630. } else {
  631. hr = StringCchCopy (lpEnd, dwGPTPathLength - (lpEnd - pszGPTPath), TEXT("User"));
  632. }
  633. ASSERT(SUCCEEDED(hr));
  634. } else {
  635. ulResult = pLDAP->pfnLdapGetLastError();
  636. if (ulResult == LDAP_NO_SUCH_ATTRIBUTE) {
  637. if (dwFlags & GPO_LIST_FLAG_MACHINE) {
  638. DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: Machine does not have access to <%s>"), lpGPOPath));
  639. } else {
  640. DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: User does not have access to <%s>"), lpGPOPath));
  641. }
  642. if (bVerbose) {
  643. CEvents ev(FALSE, EVENT_NO_ACCESS);
  644. ev.AddArg(lpGPOPath); ev.Report();
  645. }
  646. bResult = TRUE;
  647. } else {
  648. xe = pLDAP->pfnLdapMapErrorToWin32(ulResult);
  649. DebugMsg((DM_WARNING, TEXT("ProcessGPO: GPO %s does not have a file system path, error = 0x%x."), lpGPOPath, ulResult));
  650. CEvents ev(TRUE, EVENT_CORRUPT_GPO_FSPATH);
  651. ev.AddArg(lpGPOPath); ev.Report();
  652. }
  653. goto Exit;
  654. }
  655. //
  656. // In the results, get the values that match the common name attribute
  657. //
  658. lpValues = pLDAP->pfnldap_get_values(pld, pMessage, szCommonName);
  659. if (lpValues && ValidateGuid(*lpValues)) {
  660. DmAssert( lstrlen(*lpValues) < 80 );
  661. hr = StringCchCopy (szGPOName, ARRAYSIZE(szGPOName), *lpValues);
  662. if (FAILED(hr)) {
  663. xe = ERROR_INSUFFICIENT_BUFFER;
  664. CEvents ev(TRUE, EVENT_CORRUPT_GPO_COMMONNAME);
  665. ev.AddArg(lpGPOPath); ev.Report();
  666. goto Exit;
  667. }
  668. DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: Found common name of: <%s>"), szGPOName));
  669. pLDAP->pfnldap_value_free (lpValues);
  670. } else {
  671. ulResult = pLDAP->pfnLdapGetLastError();
  672. xe = pLDAP->pfnLdapMapErrorToWin32(ulResult);
  673. DebugMsg((DM_WARNING, TEXT("ProcessGPO: GPO %s does not have a common name (a GUID)."), lpGPOPath));
  674. CEvents ev(TRUE, EVENT_CORRUPT_GPO_COMMONNAME);
  675. ev.AddArg(lpGPOPath); ev.Report();
  676. goto Exit;
  677. }
  678. //
  679. // In the results, get the values that match the display name attribute
  680. //
  681. lpValues = pLDAP->pfnldap_get_values(pld, pMessage, szDisplayName);
  682. if (lpValues) {
  683. DWORD dwFriendlyLength = lstrlen(*lpValues)+1;
  684. pszFriendlyName = (LPWSTR) LocalAlloc( LPTR, (dwFriendlyLength) * sizeof(TCHAR) );
  685. if ( pszFriendlyName == 0) {
  686. xe = GetLastError();
  687. DebugMsg((DM_WARNING, TEXT("ProcessGPO: Unable to allocate memory")));
  688. pLDAP->pfnldap_value_free (lpValues);
  689. goto Exit;
  690. }
  691. hr = StringCchCopy (pszFriendlyName, dwFriendlyLength, *lpValues);
  692. ASSERT(SUCCEEDED(hr));
  693. DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: Found display name of: <%s>"), pszFriendlyName));
  694. pLDAP->pfnldap_value_free (lpValues);
  695. } else {
  696. DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: No display name for this object.")));
  697. pszFriendlyName = (LPWSTR) LocalAlloc( LPTR, 2 * sizeof(TCHAR) );
  698. if ( pszFriendlyName == 0) {
  699. xe = GetLastError();
  700. DebugMsg((DM_WARNING, TEXT("ProcessGPO: Unable to allocate memory")));
  701. goto Exit;
  702. }
  703. pszFriendlyName[0] = TEXT('\0');
  704. }
  705. //
  706. // In the results, get the values that match the version attribute
  707. //
  708. lpValues = pLDAP->pfnldap_get_values(pld, pMessage, szVersion);
  709. if (lpValues) {
  710. dwVersion = StringToInt (*lpValues);
  711. if (dwFlags & GPO_LIST_FLAG_MACHINE) {
  712. dwVersion = MAKELONG(LOWORD(dwVersion), LOWORD(dwGPTVersion));
  713. DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: Found machine version of: GPC is %d, GPT is %d"), LOWORD(dwVersion), HIWORD(dwVersion)));
  714. } else {
  715. dwVersion = MAKELONG(HIWORD(dwVersion), HIWORD(dwGPTVersion));
  716. DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: Found user version of: GPC is %d, GPT is %d"), LOWORD(dwVersion), HIWORD(dwVersion)));
  717. }
  718. pLDAP->pfnldap_value_free (lpValues);
  719. } else {
  720. // start treating this as an error.
  721. xe = pLDAP->pfnLdapMapErrorToWin32(pLDAP->pfnLdapGetLastError());
  722. DebugMsg((DM_WARNING, TEXT("ProcessGPO: GPO %s does not have a version number."), lpGPOPath));
  723. CEvents ev(TRUE, EVENT_NODSVERSION);
  724. ev.AddArg(lpGPOPath); ev.AddArgLdapError(pLDAP->pfnLdapGetLastError()); ev.Report();
  725. goto Exit;
  726. }
  727. //
  728. // In the results, get the values that match the flags attribute
  729. //
  730. lpValues = pLDAP->pfnldap_get_values(pld, pMessage, szFlags);
  731. if (lpValues) {
  732. dwGPOFlags = StringToInt (*lpValues);
  733. DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: Found flags of: %d"), dwGPOFlags));
  734. pLDAP->pfnldap_value_free (lpValues);
  735. } else {
  736. DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: No flags for this object.")));
  737. }
  738. //
  739. // In the results, get the values that match the extension names attribute
  740. //
  741. lpValues = pLDAP->pfnldap_get_values(pld, pMessage,
  742. (dwFlags & GPO_LIST_FLAG_MACHINE) ? GPO_MACHEXTENSION_NAMES
  743. : GPO_USEREXTENSION_NAMES );
  744. if (lpValues) {
  745. if ( lstrcmpi( *lpValues, TEXT(" ") ) == 0 ) {
  746. //
  747. // A blank char is also a null property case, because Adsi doesn't commit null strings
  748. //
  749. DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: No client-side extensions for this object.")));
  750. } else {
  751. DWORD dwExtLength = lstrlen(*lpValues)+1;
  752. pszExtensions = (LPWSTR) LocalAlloc( LPTR, (dwExtLength) * sizeof(TCHAR) );
  753. if ( pszExtensions == 0 ) {
  754. xe = GetLastError();
  755. DebugMsg((DM_WARNING, TEXT("ProcessGPO: Unable to allocate memory")));
  756. pLDAP->pfnldap_value_free (lpValues);
  757. goto Exit;
  758. }
  759. hr = StringCchCopy( pszExtensions, dwExtLength, *lpValues );
  760. ASSERT(SUCCEEDED(hr));
  761. DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: Found extensions: %s"), pszExtensions));
  762. }
  763. pLDAP->pfnldap_value_free (lpValues);
  764. } else {
  765. DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: No client-side extensions for this object.")));
  766. }
  767. //
  768. // Log which GPO we found
  769. //
  770. if (bVerbose) {
  771. CEvents ev(FALSE, EVENT_FOUND_GPO);
  772. ev.AddArg(pszFriendlyName); ev.AddArg(szGPOName); ev.Report();
  773. }
  774. //
  775. // Check the functionalty version number
  776. //
  777. if (dwFunctionalityVersion < 2) {
  778. DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: GPO %s was created by an old version of the Group Policy Editor. It will be skipped."), pszFriendlyName));
  779. if (bVerbose) {
  780. CEvents ev(FALSE, EVENT_GPO_TOO_OLD);
  781. ev.AddArg(pszFriendlyName); ev.Report();
  782. }
  783. bOldGpoVersion = TRUE;
  784. }
  785. //
  786. // Check if the GPO is disabled
  787. //
  788. if (((dwFlags & GPO_LIST_FLAG_MACHINE) &&
  789. (dwGPOFlags & GPO_OPTION_DISABLE_MACHINE)) ||
  790. (!(dwFlags & GPO_LIST_FLAG_MACHINE) &&
  791. (dwGPOFlags & GPO_OPTION_DISABLE_USER))) {
  792. DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: GPO %s is disabled. It will be skipped."), pszFriendlyName));
  793. if (bVerbose) {
  794. CEvents ev(FALSE, EVENT_GPO_DISABLED);
  795. ev.AddArg(pszFriendlyName); ev.Report();
  796. }
  797. bDisabled = TRUE;
  798. }
  799. //
  800. // Check if the version number is 0, if so there isn't any data
  801. // in the GPO and we can skip it
  802. //
  803. if (dwVersion == 0) {
  804. DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: GPO %s doesn't contain any data since the version number is 0. It will be skipped."), pszFriendlyName));
  805. if (bVerbose) {
  806. CEvents ev(FALSE, EVENT_GPO_NO_DATA);
  807. ev.AddArg(pszFriendlyName); ev.Report();
  808. }
  809. bNoGpoData = TRUE;
  810. }
  811. //
  812. // Put the correct container name on the front of the LDAP path
  813. //
  814. DWORD dwTempLength = lstrlen(lpGPOPath) + 20;
  815. lpTemp = (LPWSTR) LocalAlloc (LPTR, (dwTempLength) * sizeof(TCHAR));
  816. if (!lpTemp) {
  817. xe = GetLastError();
  818. DebugMsg((DM_WARNING, TEXT("ProcessGPO: Failed to allocate memory with %d"), GetLastError()));
  819. CEvents ev(TRUE, EVENT_OUT_OF_MEMORY);
  820. ev.AddArgWin32Error(GetLastError()); ev.Report();
  821. goto Exit;
  822. }
  823. if (dwFlags & GPO_LIST_FLAG_MACHINE) {
  824. hr = StringCchCopy (lpTemp, dwTempLength, TEXT("LDAP://CN=Machine,"));
  825. } else {
  826. hr = StringCchCopy (lpTemp, dwTempLength, TEXT("LDAP://CN=User,"));
  827. }
  828. ASSERT(SUCCEEDED(hr));
  829. hr = StringCchCat (lpTemp, dwTempLength, lpPath);
  830. ASSERT(SUCCEEDED(hr));
  831. //
  832. // Add this GPO to the list
  833. //
  834. if ( bRsopLogging ) {
  835. bResult = AddGPOToRsopList( ppGpContainerList,
  836. dwFlags,
  837. TRUE,
  838. bAccessGranted,
  839. bDisabled,
  840. dwVersion,
  841. lpTemp,
  842. pszGPTPath,
  843. pszFriendlyName,
  844. szGPOName,
  845. pSD,
  846. cbSDLen,
  847. bFilterAllowed,
  848. pwszFilterId,
  849. lpDSObject,
  850. dwGPOOptions );
  851. if (!bResult) {
  852. xe = GetLastError();
  853. LocalFree(lpTemp);
  854. goto Exit;
  855. }
  856. }
  857. if ( bProcessGPO && bAccessGranted && !bOldGpoVersion && !bDisabled && !bNoGpoData && bFilterAllowed)
  858. {
  859. bResult = AddGPO (lpGPOList, dwFlags, TRUE, bAccessGranted, bDisabled,
  860. dwGPOOptions, dwVersion, lpTemp,
  861. pszGPTPath, pszFriendlyName, szGPOName, pszExtensions, pSD, cbSDLen, GPOLink, lpDSObject, 0,
  862. FALSE, bBlock, bVerbose, bProcessGPO);
  863. }
  864. if (!bResult) {
  865. xe = GetLastError();
  866. DebugMsg((DM_WARNING, TEXT("ProcessGPO: Failed to add GPO <%s> to the list."), pszFriendlyName));
  867. }
  868. LocalFree (lpTemp);
  869. Exit:
  870. if ( pSD )
  871. LocalFree( pSD );
  872. if ( pszGPTPath )
  873. LocalFree( pszGPTPath );
  874. if ( pszFriendlyName )
  875. LocalFree( pszFriendlyName );
  876. if ( pszExtensions )
  877. LocalFree( pszExtensions );
  878. if ( pwszFilterId )
  879. LocalFree( pwszFilterId );
  880. if (pMessage && bOwnLdapMsg ) {
  881. pLDAP->pfnldap_msgfree (pMessage);
  882. }
  883. DebugMsg((DM_VERBOSE, TEXT("ProcessGPO: ==============================")));
  884. return bResult;
  885. }
  886. //*************************************************************
  887. //
  888. // SearchDSObject()
  889. //
  890. // Purpose: Searches the specified DS object for GPOs and
  891. // if found, adds them to the list.
  892. //
  893. // Parameters: lpDSObject - DS object to search
  894. // dwFlags - GetGPOList & GP_PLANMODE flags
  895. // pGPOForcedList - List of forced GPOs
  896. // pGPONonForcedList - List of non-forced GPOs
  897. // ppSOMList - List of LSDOUs
  898. // ppGpContainerList - List of Gp Containers
  899. // bVerbose - Verbose output
  900. // GPOLink - GPO link type
  901. // pld - LDAP info
  902. // pLDAP - LDAP api
  903. // bBlock - Pointer to the block flag
  904. //
  905. //
  906. // Return: TRUE if successful
  907. // FALSE if an error occurs
  908. //
  909. //*************************************************************
  910. BOOL SearchDSObject (LPTSTR lpDSObject, DWORD dwFlags, HANDLE hToken, PGROUP_POLICY_OBJECT *pGPOForcedList,
  911. PGROUP_POLICY_OBJECT *pGPONonForcedList,
  912. LPSCOPEOFMGMT *ppSOMList, LPGPCONTAINER *ppGpContainerList,
  913. BOOL bVerbose,
  914. GPO_LINK GPOLink, PLDAP pld, PLDAP_API pLDAP, PLDAPMessage pLDAPMsg,BOOL *bBlock, PRSOPTOKEN pRsopToken )
  915. {
  916. PGROUP_POLICY_OBJECT pForced = NULL, pNonForced = NULL, lpGPO;
  917. LPTSTR *lpValues;
  918. ULONG ulResult;
  919. BOOL bResult = FALSE;
  920. BOOL bOwnLdapMsg = FALSE; // LDAP message owned by us (if true) or caller (if false)
  921. DWORD dwGPOOptions, dwOptions = 0;
  922. LPTSTR lpTemp, lpList, lpDSClass;
  923. BYTE berValue[8];
  924. LDAPControl SeInfoControl = { LDAP_SERVER_SD_FLAGS_OID_W, { 5, (PCHAR)berValue }, TRUE };
  925. PLDAPControl ServerControls[] = { &SeInfoControl, NULL };
  926. TCHAR szGPLink[] = TEXT("gPLink");
  927. TCHAR szGPOPath[512];
  928. TCHAR szGPOOptions[12];
  929. TCHAR szGPOptions[] = TEXT("gPOptions");
  930. TCHAR szSDProperty[] = TEXT("nTSecurityDescriptor");
  931. ULONG i = 0;
  932. LPTSTR lpFullDSObject = NULL;
  933. BOOL bFound = FALSE;
  934. LPTSTR lpAttr[] = { szGPLink,
  935. szGPOptions,
  936. // szObjectClass, not needed
  937. szSDProperty,
  938. NULL
  939. };
  940. SCOPEOFMGMT *pSOM = NULL;
  941. BOOL bRsopLogging = (ppSOMList != NULL);
  942. BOOL bAllGPOs = (dwFlags & FLAG_NO_GPO_FILTER) && (dwFlags & GP_PLANMODE);
  943. XLastError xe;
  944. HRESULT hr = S_OK;
  945. //
  946. // Setup the BER encoding for the SD
  947. //
  948. berValue[0] = 0x30;
  949. berValue[1] = 0x03;
  950. berValue[2] = 0x02; // denotes an integer
  951. berValue[3] = 0x01; // denotes size
  952. berValue[4] = (BYTE)((DACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION) & 0xF);
  953. if ( !pRsopToken )
  954. {
  955. //
  956. // if it is not planning mode, don't get the SD
  957. //
  958. lpAttr[2] = NULL;
  959. ServerControls[0] = NULL;
  960. }
  961. //
  962. // Search for the object
  963. //
  964. DebugMsg((DM_VERBOSE, TEXT("SearchDSObject: Searching <%s>"), lpDSObject));
  965. if (bVerbose) {
  966. CEvents ev(FALSE, EVENT_SEARCHING);
  967. ev.AddArg(lpDSObject); ev.Report();
  968. }
  969. if ( bRsopLogging )
  970. {
  971. pSOM = AllocSOM( lpDSObject );
  972. if ( !pSOM ) {
  973. xe = GetLastError();
  974. DebugMsg((DM_WARNING, TEXT("SearchDSObject: Unable to allocate memory for SOM object. Leaving. ")));
  975. goto Exit;
  976. }
  977. pSOM->dwType = GPOLink;
  978. pSOM->bBlocked = *bBlock;
  979. }
  980. if ( pLDAPMsg == NULL ) {
  981. bOwnLdapMsg = TRUE;
  982. ulResult = pLDAP->pfnldap_search_ext_s(pld, lpDSObject, LDAP_SCOPE_BASE,
  983. szDSClassAny, lpAttr, FALSE,
  984. (PLDAPControl*)ServerControls,
  985. NULL, NULL, 0, &pLDAPMsg);
  986. if (ulResult != LDAP_SUCCESS) {
  987. if (ulResult == LDAP_NO_SUCH_ATTRIBUTE) {
  988. DebugMsg((DM_VERBOSE, TEXT("SearchDSObject: No GPO(s) for this object.")));
  989. if (bVerbose) {
  990. CEvents ev(FALSE, EVENT_NO_GPOS); ev.AddArg(lpDSObject); ev.Report();
  991. }
  992. bResult = TRUE;
  993. } else if (ulResult == LDAP_NO_SUCH_OBJECT) {
  994. DebugMsg((DM_VERBOSE, TEXT("SearchDSObject: Object not found in DS (this is ok). Leaving. ")));
  995. if (bVerbose) {
  996. CEvents ev(FALSE, EVENT_NO_DS_OBJECT);
  997. ev.AddArg(lpDSObject); ev.Report();
  998. }
  999. bResult = TRUE;
  1000. } else if (ulResult == LDAP_SIZELIMIT_EXCEEDED) {
  1001. xe = pLDAP->pfnLdapMapErrorToWin32(ulResult);
  1002. DebugMsg((DM_WARNING, TEXT("SearchDSObject: Too many linked GPOs in search.") ));
  1003. CEvents ev(TRUE, EVENT_TOO_MANY_GPOS); ev.Report();
  1004. } else {
  1005. xe = pLDAP->pfnLdapMapErrorToWin32(ulResult);
  1006. DebugMsg((DM_VERBOSE, TEXT("SearchDSObject: Failed to find DS object <%s> due to error %d."),
  1007. lpDSObject, ulResult));
  1008. CEvents ev(TRUE, EVENT_GPLINK_NOT_FOUND);
  1009. ev.AddArg(lpDSObject); ev.AddArgLdapError(ulResult); ev.Report();
  1010. }
  1011. goto Exit;
  1012. }
  1013. }
  1014. if ( bRsopLogging && pRsopToken && !bAllGPOs )
  1015. {
  1016. //
  1017. // In Rsop planning mode, check access to OU
  1018. //
  1019. BOOL bAccessGranted = FALSE;
  1020. BOOL bOk;
  1021. bOk = CheckOUAccess(pLDAP,
  1022. pld,
  1023. pLDAPMsg,
  1024. pRsopToken,
  1025. &bAccessGranted );
  1026. if ( !bOk )
  1027. {
  1028. xe = GetLastError();
  1029. goto Exit;
  1030. }
  1031. if ( !bAccessGranted )
  1032. {
  1033. //
  1034. // no access for the user on the OU. Exit
  1035. //
  1036. DebugMsg((DM_VERBOSE, TEXT("SearchDSObject: Access denied in planning mode to SOM <%s>"), lpDSObject));
  1037. if (pLDAPMsg && bOwnLdapMsg )
  1038. {
  1039. pLDAP->pfnldap_msgfree (pLDAPMsg);
  1040. pLDAPMsg = 0;
  1041. }
  1042. CEvents ev(TRUE, EVENT_OU_ACCESSDENIED);
  1043. ev.AddArg(lpDSObject); ev.Report();
  1044. goto Exit;
  1045. }
  1046. }
  1047. //
  1048. // In the results, get the values that match the gPOptions attribute
  1049. //
  1050. lpValues = pLDAP->pfnldap_get_values(pld, pLDAPMsg, szGPOptions);
  1051. if (lpValues && *lpValues) {
  1052. dwOptions = StringToInt (*lpValues);
  1053. pLDAP->pfnldap_value_free (lpValues);
  1054. }
  1055. //
  1056. // In the results, get the values that match the gPLink attribute
  1057. //
  1058. lpValues = pLDAP->pfnldap_get_values(pld, pLDAPMsg, szGPLink);
  1059. if (lpValues && *lpValues) {
  1060. lpList = *lpValues;
  1061. DebugMsg((DM_VERBOSE, TEXT("SearchDSObject: Found GPO(s): <%s>"), lpList));
  1062. DWORD dwFullLength = lstrlen(lpDSObject) + 8;
  1063. lpFullDSObject = (LPWSTR) LocalAlloc (LPTR, (dwFullLength) * sizeof(TCHAR));
  1064. if (!lpFullDSObject) {
  1065. xe = GetLastError();
  1066. DebugMsg((DM_WARNING, TEXT("SearchDSObject: Failed to allocate memory for full DS Object path name with %d"),
  1067. GetLastError()));
  1068. pLDAP->pfnldap_value_free (lpValues);
  1069. goto Exit;
  1070. }
  1071. hr = StringCchCopy (lpFullDSObject, dwFullLength, TEXT("LDAP://"));
  1072. ASSERT(SUCCEEDED(hr));
  1073. hr = StringCchCat (lpFullDSObject, dwFullLength, lpDSObject);
  1074. ASSERT(SUCCEEDED(hr));
  1075. while (*lpList) {
  1076. DWORD dwLenRemaining;
  1077. //
  1078. // Pull off the GPO ldap path
  1079. //
  1080. lpTemp = szGPOPath;
  1081. dwLenRemaining = (ARRAYSIZE(szGPOPath))-1; // (len of array) - (end of string character)
  1082. dwGPOOptions = 0;
  1083. while (*lpList && (*lpList != TEXT('['))) {
  1084. lpList++;
  1085. }
  1086. if (!(*lpList)) {
  1087. break;
  1088. }
  1089. lpList++;
  1090. while ((dwLenRemaining) && *lpList && (*lpList != TEXT(';'))) {
  1091. *lpTemp++ = *lpList++;
  1092. dwLenRemaining--;
  1093. }
  1094. if (*lpList != TEXT(';')) {
  1095. break;
  1096. }
  1097. *lpTemp = TEXT('\0');
  1098. lpList++;
  1099. lpTemp = szGPOOptions;
  1100. dwLenRemaining = (ARRAYSIZE(szGPOOptions))-1; // (len of array) - (end of string character)
  1101. *lpTemp = TEXT('\0');
  1102. while ((dwLenRemaining) && *lpList && (*lpList != TEXT(']'))) {
  1103. *lpTemp++ = *lpList++;
  1104. dwLenRemaining--;
  1105. }
  1106. if (*lpList != TEXT(']')) {
  1107. break;
  1108. }
  1109. *lpTemp = TEXT('\0');
  1110. lpList++;
  1111. dwGPOOptions = StringToInt (szGPOOptions);
  1112. if ( bRsopLogging ) {
  1113. GPLINK *pGpLink = AllocGpLink( szGPOPath, dwGPOOptions );
  1114. if ( pGpLink == NULL ) {
  1115. xe = GetLastError();
  1116. DebugMsg((DM_WARNING, TEXT("SearchDSObject: Unable to allocate memory for GpLink object. Leaving. ")));
  1117. goto Exit;
  1118. }
  1119. //
  1120. // Append GpLink to end of SOM list
  1121. //
  1122. if ( pSOM->pGpLinkList == NULL ) {
  1123. pSOM->pGpLinkList = pGpLink;
  1124. } else {
  1125. GPLINK *pTrailPtr = NULL;
  1126. GPLINK *pCurPtr = pSOM->pGpLinkList;
  1127. while ( pCurPtr != NULL ) {
  1128. pTrailPtr = pCurPtr;
  1129. pCurPtr = pCurPtr->pNext;
  1130. }
  1131. pTrailPtr->pNext = pGpLink;
  1132. }
  1133. }
  1134. //
  1135. // Check if this link is disabled
  1136. //
  1137. BOOL bProcessGPO = TRUE;
  1138. if ( ( dwGPOOptions & GPO_FLAG_DISABLE ) && !bAllGPOs )
  1139. {
  1140. DebugMsg((DM_VERBOSE, TEXT("SearchDSObject: The link to GPO %s is disabled. It will be skipped for processing."), szGPOPath));
  1141. if (bVerbose)
  1142. {
  1143. CEvents ev(FALSE, EVENT_GPO_LINK_DISABLED);
  1144. ev.AddArg(szGPOPath); ev.Report();
  1145. }
  1146. bProcessGPO = FALSE;
  1147. }
  1148. if (bProcessGPO || (dwFlags & GP_PLANMODE)) {
  1149. if (!bProcessGPO) {
  1150. DebugMsg((DM_VERBOSE, TEXT("SearchDSObject: The link to GPO %s is disabled. GPO is still being queried. Planning mode."), szGPOPath));
  1151. }
  1152. if ( !ProcessGPO( szGPOPath,
  1153. dwFlags,
  1154. hToken,
  1155. (dwGPOOptions & GPO_FLAG_FORCE) ? &pForced : &pNonForced,
  1156. ppGpContainerList,
  1157. dwGPOOptions,
  1158. TRUE,
  1159. bVerbose,
  1160. GPOLink,
  1161. lpFullDSObject,
  1162. pld,
  1163. pLDAP,
  1164. 0,
  1165. *bBlock,
  1166. pRsopToken,
  1167. 0,
  1168. 0,
  1169. bProcessGPO ) )
  1170. {
  1171. xe = GetLastError();
  1172. DebugMsg((DM_WARNING, TEXT("SearchDSObject: ProcessGPO failed.")));
  1173. pLDAP->pfnldap_value_free (lpValues);
  1174. goto Exit;
  1175. }
  1176. }
  1177. }
  1178. pLDAP->pfnldap_value_free (lpValues);
  1179. //
  1180. // Set the block flag now if requested. This way OU's, domains, etc
  1181. // higher in the namespace will have GPOs removed if appropriate
  1182. //
  1183. if (dwOptions & GPC_BLOCK_POLICY) {
  1184. *bBlock = TRUE;
  1185. if ( bRsopLogging )
  1186. pSOM->bBlocking = TRUE;
  1187. DebugMsg((DM_VERBOSE, TEXT("SearchDSObject: <%s> has the Block From Above attribute set"), lpDSObject));
  1188. if (bVerbose) {
  1189. CEvents ev(FALSE, EVENT_BLOCK_ENABLED);
  1190. ev.AddArg(lpDSObject); ev.Report();
  1191. }
  1192. }
  1193. } else {
  1194. DebugMsg((DM_VERBOSE, TEXT("SearchDSObject: No GPO(s) for this object.")));
  1195. if (bVerbose) {
  1196. CEvents ev(FALSE, EVENT_NO_GPOS); ev.AddArg(lpDSObject); ev.Report();
  1197. }
  1198. }
  1199. //
  1200. // Merge the temp and real lists together
  1201. // First the non-forced lists
  1202. //
  1203. if (pNonForced) {
  1204. lpGPO = pNonForced;
  1205. while (lpGPO->pNext) {
  1206. lpGPO = lpGPO->pNext;
  1207. }
  1208. lpGPO->pNext = *pGPONonForcedList;
  1209. if (*pGPONonForcedList) {
  1210. (*pGPONonForcedList)->pPrev = lpGPO;
  1211. }
  1212. *pGPONonForcedList = pNonForced;
  1213. }
  1214. //
  1215. // Now the forced lists
  1216. //
  1217. if (pForced) {
  1218. lpGPO = *pGPOForcedList;
  1219. if (lpGPO) {
  1220. while (lpGPO->pNext) {
  1221. lpGPO = lpGPO->pNext;
  1222. }
  1223. lpGPO->pNext = pForced;
  1224. pForced->pPrev = lpGPO;
  1225. } else {
  1226. *pGPOForcedList = pForced;
  1227. }
  1228. }
  1229. bResult = TRUE;
  1230. Exit:
  1231. if ( !bResult && pSOM != NULL ) {
  1232. FreeSOM( pSOM );
  1233. }
  1234. else {
  1235. if ( bResult && bRsopLogging ) {
  1236. //
  1237. // Insert SOM at the beginning
  1238. //
  1239. pSOM->pNext = *ppSOMList;
  1240. *ppSOMList = pSOM;
  1241. }
  1242. }
  1243. if (lpFullDSObject) {
  1244. LocalFree (lpFullDSObject);
  1245. }
  1246. if (pLDAPMsg && bOwnLdapMsg ) {
  1247. pLDAP->pfnldap_msgfree (pLDAPMsg);
  1248. }
  1249. return bResult;
  1250. }
  1251. //*************************************************************
  1252. //
  1253. // AllocDnEntry()
  1254. //
  1255. // Purpose: Allocates a new struct for dn entry
  1256. //
  1257. //
  1258. // Parameters: pwszDN - Distinguished name
  1259. //
  1260. // Return: Pointer if successful
  1261. // NULL if an error occurs
  1262. //
  1263. //*************************************************************
  1264. DNENTRY * AllocDnEntry( LPTSTR pwszDN )
  1265. {
  1266. DNENTRY *pDnEntry = (DNENTRY *) LocalAlloc (LPTR, sizeof(DNENTRY));
  1267. XLastError xe;
  1268. HRESULT hr = S_OK;
  1269. if ( pDnEntry == NULL ) {
  1270. xe = GetLastError();
  1271. DebugMsg((DM_WARNING, TEXT("AllocDnEntry: Failed to alloc pDnEntry with 0x%x."),
  1272. GetLastError()));
  1273. return NULL;
  1274. }
  1275. pDnEntry->pwszDN = (LPTSTR) LocalAlloc (LPTR, (lstrlen(pwszDN) + 1) * sizeof(TCHAR) );
  1276. if ( pDnEntry->pwszDN == NULL ) {
  1277. xe = GetLastError();
  1278. DebugMsg((DM_WARNING, TEXT("AllocDnEntry: Failed to alloc pwszDN with 0x%x."),
  1279. GetLastError()));
  1280. LocalFree( pDnEntry );
  1281. return NULL;
  1282. }
  1283. hr = StringCchCopy( pDnEntry->pwszDN, lstrlen(pwszDN) + 1, pwszDN );
  1284. ASSERT(SUCCEEDED(hr));
  1285. return pDnEntry;
  1286. }
  1287. //*************************************************************
  1288. //
  1289. // FreeDnEntry()
  1290. //
  1291. // Purpose: Frees dn entry struct
  1292. //
  1293. //*************************************************************
  1294. void FreeDnEntry( DNENTRY *pDnEntry )
  1295. {
  1296. if ( pDnEntry ) {
  1297. if ( pDnEntry->pwszDN )
  1298. LocalFree( pDnEntry->pwszDN );
  1299. LocalFree( pDnEntry );
  1300. }
  1301. }
  1302. //*************************************************************
  1303. //
  1304. // AllocLdapQuery()
  1305. //
  1306. // Purpose: Allocates a new struct for ldap query
  1307. //
  1308. //
  1309. // Parameters: pwszDomain - Domain of Gpo
  1310. //
  1311. // Return: Pointer if successful
  1312. // NULL if an error occurs
  1313. //
  1314. //*************************************************************
  1315. LDAPQUERY * AllocLdapQuery( LPTSTR pwszDomain )
  1316. {
  1317. const INIT_ALLOC_SIZE = 1000;
  1318. LDAPQUERY *pQuery = (LDAPQUERY *) LocalAlloc (LPTR, sizeof(LDAPQUERY));
  1319. XLastError xe;
  1320. HRESULT hr = S_OK;
  1321. if ( pQuery == NULL ) {
  1322. xe = GetLastError();
  1323. DebugMsg((DM_WARNING, TEXT("AllocLdapQuery: Failed to alloc pQuery with 0x%x."),
  1324. GetLastError()));
  1325. return NULL;
  1326. }
  1327. pQuery->pwszDomain = (LPTSTR) LocalAlloc (LPTR, (lstrlen(pwszDomain) + 1) * sizeof(TCHAR) );
  1328. if ( pQuery->pwszDomain == NULL ) {
  1329. xe = GetLastError();
  1330. DebugMsg((DM_WARNING, TEXT("AllocLdapQuery: Failed to alloc pwszDomain with 0x%x."),
  1331. GetLastError()));
  1332. LocalFree( pQuery );
  1333. return NULL;
  1334. }
  1335. pQuery->pwszFilter = (LPTSTR) LocalAlloc (LPTR, INIT_ALLOC_SIZE );
  1336. if ( pQuery->pwszFilter == NULL ) {
  1337. xe = GetLastError();
  1338. DebugMsg((DM_WARNING, TEXT("AllocLdapQuery: Failed to alloc pwszFilter with 0x%x."),
  1339. GetLastError()));
  1340. LocalFree( pQuery->pwszDomain );
  1341. LocalFree( pQuery );
  1342. return NULL;
  1343. }
  1344. hr = StringCchCopy( pQuery->pwszDomain, lstrlen(pwszDomain) + 1, pwszDomain );
  1345. ASSERT(SUCCEEDED(hr));
  1346. hr = StringCchCopy( pQuery->pwszFilter, INIT_ALLOC_SIZE, L"(|)" );
  1347. ASSERT(SUCCEEDED(hr));
  1348. pQuery->cbLen = 8; // 8 = (lstrlen(L"(|)") + 1) * sizeof(TCHAR)
  1349. pQuery->cbAllocLen = INIT_ALLOC_SIZE;
  1350. return pQuery;
  1351. }
  1352. //*************************************************************
  1353. //
  1354. // FreeLdapQuery()
  1355. //
  1356. // Purpose: Frees ldap query struct
  1357. //
  1358. //*************************************************************
  1359. void FreeLdapQuery( PLDAP_API pLDAP, LDAPQUERY *pQuery )
  1360. {
  1361. DNENTRY *pDnEntry = NULL;
  1362. if ( pQuery ) {
  1363. if ( pQuery->pwszDomain )
  1364. LocalFree( pQuery->pwszDomain );
  1365. if ( pQuery->pwszFilter )
  1366. LocalFree( pQuery->pwszFilter );
  1367. if ( pQuery->pMessage )
  1368. pLDAP->pfnldap_msgfree( pQuery->pMessage );
  1369. if ( pQuery->pLdapHandle && pQuery->bOwnLdapHandle )
  1370. pLDAP->pfnldap_unbind( pQuery->pLdapHandle );
  1371. pDnEntry = pQuery->pDnEntry;
  1372. while ( pDnEntry ) {
  1373. DNENTRY *pTemp = pDnEntry->pNext;
  1374. FreeDnEntry( pDnEntry );
  1375. pDnEntry = pTemp;
  1376. }
  1377. LocalFree( pQuery );
  1378. }
  1379. }
  1380. //*************************************************************
  1381. //
  1382. // MatchDnWithDeferredItems()
  1383. //
  1384. // Purpose: Matches the dns from ldap query with the deferred items
  1385. //
  1386. // Parameters: pLDAP - LDAP function table pointer
  1387. // ppLdapQuery - LDAP query list
  1388. //
  1389. // Return: TRUE if successful
  1390. // FALSE if an error occurs
  1391. //
  1392. //*************************************************************
  1393. BOOL MatchDnWithDeferredItems( PLDAP_API pLDAP, LDAPQUERY *pLdapQuery, BOOL bOUProcessing )
  1394. {
  1395. PLDAPMessage pMsg = pLDAP->pfnldap_first_entry( pLdapQuery->pLdapHandle, pLdapQuery->pMessage );
  1396. while ( pMsg ) {
  1397. WCHAR *pwszDN = pLDAP->pfnldap_get_dn( pLdapQuery->pLdapHandle, pMsg ); // fixing bug 568263
  1398. if (!pwszDN)
  1399. {
  1400. return FALSE;
  1401. }
  1402. DNENTRY *pCurPtr = pLdapQuery->pDnEntry;
  1403. while ( pCurPtr ) {
  1404. INT iResult = CompareString ( LOCALE_INVARIANT, NORM_IGNORECASE,
  1405. pwszDN, -1, pCurPtr->pwszDN, -1 );
  1406. if ( iResult == CSTR_EQUAL ) {
  1407. //
  1408. // Store the pointer to ldap message so that it can be used
  1409. // later to retrieve necessary attributes.
  1410. //
  1411. if ( bOUProcessing )
  1412. pCurPtr->pDeferredOU->pOUMsg = pMsg;
  1413. else {
  1414. LPGPOPROCDATA lpGpoProcData = (LPGPOPROCDATA)pCurPtr->pDeferredGPO->lParam2;
  1415. pCurPtr->pDeferredGPO->lParam = (LPARAM) pMsg;
  1416. lpGpoProcData->pLdapHandle = pLdapQuery->pLdapHandle;
  1417. }
  1418. pCurPtr = pCurPtr->pNext;
  1419. } else if ( iResult == CSTR_LESS_THAN ) {
  1420. //
  1421. // Since dns are in ascending order,
  1422. // we are done.
  1423. //
  1424. break;
  1425. } else {
  1426. //
  1427. // Advance down the list
  1428. //
  1429. pCurPtr = pCurPtr->pNext;
  1430. } // final else
  1431. } // while pcurptr
  1432. pLDAP->pfnldap_memfree( pwszDN );
  1433. pMsg = pLDAP->pfnldap_next_entry( pLdapQuery->pLdapHandle, pMsg );
  1434. } // while pmsg
  1435. return TRUE;
  1436. }
  1437. LPWSTR DsQuoteSearchFilter( LPCWSTR );
  1438. //*************************************************************
  1439. //
  1440. // AddDnToFilter()
  1441. //
  1442. // Purpose: ORs in the new dn to the ldap filter
  1443. //
  1444. // Parameters: ppLdapQuery - LDAP query list
  1445. // pGPO - Deferred GPO
  1446. //
  1447. // Return: TRUE if successful
  1448. // FALSE if an error occurs
  1449. //
  1450. //*************************************************************
  1451. BOOL AddDnToFilter( LDAPQUERY *pLdapQuery, LPTSTR pwszDN )
  1452. {
  1453. const DN_SIZE = 20; // 20 = # chars in "(dis..=)"
  1454. BOOL bSuccess = FALSE;
  1455. LPWSTR szQuotedDN;
  1456. HRESULT hr = S_OK;
  1457. szQuotedDN = DsQuoteSearchFilter( pwszDN );
  1458. if ( ! szQuotedDN )
  1459. {
  1460. DebugMsg((DM_WARNING, TEXT("GetGPOInfo: DsQuoteSearchFilter failed with = <%d>"), GetLastError() ));
  1461. goto AddDnToFilter_ExitAndCleanup;
  1462. }
  1463. DWORD cbNew = (lstrlen(szQuotedDN) + DN_SIZE) * sizeof(TCHAR); // + 1 is not needed because \0 is already part of filter string
  1464. DWORD cbSizeRequired = pLdapQuery->cbLen + cbNew;
  1465. if ( cbSizeRequired >= pLdapQuery->cbAllocLen ) {
  1466. //
  1467. // Need to grow buffer because of overflow
  1468. //
  1469. LPTSTR pwszNewFilter = (LPTSTR) LocalAlloc (LPTR, cbSizeRequired * 2);
  1470. if ( pwszNewFilter == NULL ) {
  1471. DebugMsg((DM_WARNING, TEXT("AddDnToFilter: Unable to allocate new filter string") ));
  1472. goto AddDnToFilter_ExitAndCleanup;
  1473. }
  1474. hr = StringCchCopy( pwszNewFilter, cbSizeRequired, pLdapQuery->pwszFilter );
  1475. ASSERT(SUCCEEDED(hr));
  1476. LocalFree( pLdapQuery->pwszFilter );
  1477. pLdapQuery->pwszFilter = pwszNewFilter;
  1478. pLdapQuery->cbAllocLen = cbSizeRequired * 2;
  1479. }
  1480. DmAssert( cbSizeRequired < pLdapQuery->cbAllocLen );
  1481. //
  1482. // Overwrite last ")" and then append the new dn name term
  1483. //
  1484. hr = StringCchCopy( &pLdapQuery->pwszFilter[pLdapQuery->cbLen/sizeof(WCHAR) - 2], (pLdapQuery->cbAllocLen - pLdapQuery->cbLen)/sizeof(WCHAR) + 2, L"(distinguishedName=" );
  1485. ASSERT(SUCCEEDED(hr));
  1486. hr = StringCchCat( pLdapQuery->pwszFilter, pLdapQuery->cbAllocLen/sizeof(WCHAR), szQuotedDN );
  1487. ASSERT(SUCCEEDED(hr));
  1488. hr = StringCchCat( pLdapQuery->pwszFilter, pLdapQuery->cbAllocLen/sizeof(WCHAR), L"))" );
  1489. ASSERT(SUCCEEDED(hr));
  1490. pLdapQuery->cbLen += cbNew;
  1491. bSuccess = TRUE;
  1492. AddDnToFilter_ExitAndCleanup:
  1493. if ( szQuotedDN )
  1494. {
  1495. LocalFree( szQuotedDN );
  1496. }
  1497. return bSuccess;
  1498. }
  1499. //*************************************************************
  1500. //
  1501. // InsertDN()
  1502. //
  1503. // Purpose: Adds a distinguished name entry to ldap query's
  1504. // names linked list
  1505. //
  1506. // Parameters: ppLdapQuery - LDAP query list
  1507. // pwszDN - DN
  1508. // pDeferredOU - Deferred OU
  1509. // pDeferredGPO - Deferred GPO
  1510. //
  1511. // Return: TRUE if successful
  1512. // FALSE if an error occurs
  1513. //
  1514. //*************************************************************
  1515. BOOL InsertDN( LDAPQUERY *pLdapQuery, LPTSTR pwszDN,
  1516. DNENTRY *pDeferredOU, PGROUP_POLICY_OBJECT pDeferredGPO )
  1517. {
  1518. DNENTRY *pNewEntry = NULL;
  1519. DNENTRY *pTrailPtr = NULL;
  1520. DNENTRY *pCurPtr = pLdapQuery->pDnEntry;
  1521. XLastError xe;
  1522. DmAssert( !( pDeferredOU && pDeferredGPO ) );
  1523. while ( pCurPtr != NULL ) {
  1524. INT iResult = CompareString ( LOCALE_INVARIANT, NORM_IGNORECASE,
  1525. pwszDN, -1, pCurPtr->pwszDN, -1 );
  1526. if ( iResult == CSTR_EQUAL || iResult == CSTR_LESS_THAN ) {
  1527. //
  1528. // Duplicate or since dn's are in ascending order, add new entry
  1529. //
  1530. pNewEntry = AllocDnEntry( pwszDN );
  1531. if ( pNewEntry == NULL )
  1532. return FALSE;
  1533. if ( !AddDnToFilter( pLdapQuery, pwszDN ) ) {
  1534. xe = GetLastError();
  1535. FreeDnEntry( pNewEntry );
  1536. return FALSE;
  1537. }
  1538. if ( pDeferredOU )
  1539. pNewEntry->pDeferredOU = pDeferredOU;
  1540. else
  1541. pNewEntry->pDeferredGPO = pDeferredGPO;
  1542. pNewEntry->pNext = pCurPtr;
  1543. if ( pTrailPtr == NULL )
  1544. pLdapQuery->pDnEntry = pNewEntry;
  1545. else
  1546. pTrailPtr->pNext = pNewEntry;
  1547. return TRUE;
  1548. } else {
  1549. //
  1550. // Advance down the list
  1551. //
  1552. pTrailPtr = pCurPtr;
  1553. pCurPtr = pCurPtr->pNext;
  1554. }
  1555. } // while
  1556. //
  1557. // Null list or end of list case.
  1558. //
  1559. pNewEntry = AllocDnEntry( pwszDN );
  1560. if ( pNewEntry == NULL ) {
  1561. xe = GetLastError();
  1562. return FALSE;
  1563. }
  1564. if ( !AddDnToFilter( pLdapQuery, pwszDN ) ) {
  1565. xe = GetLastError();
  1566. FreeDnEntry( pNewEntry );
  1567. return FALSE;
  1568. }
  1569. if ( pDeferredOU )
  1570. pNewEntry->pDeferredOU = pDeferredOU;
  1571. else
  1572. pNewEntry->pDeferredGPO = pDeferredGPO;
  1573. pNewEntry->pNext = pCurPtr;
  1574. if ( pTrailPtr == NULL )
  1575. pLdapQuery->pDnEntry = pNewEntry;
  1576. else
  1577. pTrailPtr->pNext = pNewEntry;
  1578. return TRUE;
  1579. }
  1580. //*************************************************************
  1581. //
  1582. // AddDN()
  1583. //
  1584. // Purpose: Adds a distinguished name entry to ldap query
  1585. //
  1586. // Parameters: ppLdapQuery - LDAP query list
  1587. // pwszDN - DN name
  1588. // pDeferredOU - Deferred OU
  1589. // pDeferredGPO - Deferred GPO
  1590. //
  1591. // Return: TRUE if successful
  1592. // FALSE if an error occurs
  1593. //
  1594. //*************************************************************
  1595. BOOL AddDN( PLDAP_API pLDAP, LDAPQUERY **ppLdapQuery,
  1596. LPTSTR pwszDN, DNENTRY *pDeferredOU, PGROUP_POLICY_OBJECT pDeferredGPO )
  1597. {
  1598. LPTSTR pwszDomain = NULL;
  1599. LPTSTR pwszTemp = pwszDN;
  1600. LDAPQUERY *pNewQuery = NULL;
  1601. LDAPQUERY *pTrailPtr = NULL;
  1602. LDAPQUERY *pCurPtr = *ppLdapQuery;
  1603. XLastError xe;
  1604. DmAssert( !( pDeferredOU && pDeferredGPO ) );
  1605. //
  1606. // Find the domain to which the GPO belongs
  1607. //
  1608. if ( pwszTemp == NULL ) {
  1609. DebugMsg((DM_WARNING, TEXT("AddDN: Null pwszDN. Exiting.") ));
  1610. return FALSE;
  1611. }
  1612. while ( *pwszTemp ) {
  1613. //
  1614. // The check below needs to be more sophisticated to take care
  1615. // of spaces in names etc.
  1616. //
  1617. if (CompareString ( LOCALE_INVARIANT, NORM_IGNORECASE,
  1618. pwszTemp, 16, TEXT("cn=configuration"), 16) == CSTR_EQUAL ) {
  1619. DebugMsg((DM_VERBOSE, TEXT("AddDN: DN %s is under cn=configuration container. queueing for rebinding"), pwszDN ));
  1620. pwszDomain = pwszTemp;
  1621. break;
  1622. }
  1623. if (CompareString ( LOCALE_INVARIANT, NORM_IGNORECASE,
  1624. pwszTemp, 3, TEXT("DC="), 3) == CSTR_EQUAL ) {
  1625. pwszDomain = pwszTemp;
  1626. break;
  1627. }
  1628. //
  1629. // Move to the next chunk of the DN name
  1630. //
  1631. while ( *pwszTemp && (*pwszTemp != TEXT(',')))
  1632. pwszTemp++;
  1633. if ( *pwszTemp == TEXT(','))
  1634. pwszTemp++;
  1635. }
  1636. if ( pwszDomain == NULL ) {
  1637. xe = ERROR_INVALID_DATA;
  1638. DebugMsg((DM_WARNING, TEXT("AddDN: Domain not found for <%s>. Exiting."), pwszDN ));
  1639. return FALSE;
  1640. }
  1641. while ( pCurPtr != NULL ) {
  1642. INT iResult = CompareString ( LOCALE_INVARIANT, NORM_IGNORECASE,
  1643. pwszDomain, -1, pCurPtr->pwszDomain, -1 );
  1644. if ( iResult == CSTR_EQUAL ) {
  1645. BOOL bOk = InsertDN( pCurPtr, pwszDN, pDeferredOU, pDeferredGPO );
  1646. return bOk;
  1647. } else if ( iResult == CSTR_LESS_THAN ) {
  1648. //
  1649. // Since domains are in ascending order,
  1650. // pwszDomain is not in list, so add.
  1651. //
  1652. pNewQuery = AllocLdapQuery( pwszDomain );
  1653. if ( pNewQuery == NULL ) {
  1654. xe = GetLastError();
  1655. return FALSE;
  1656. }
  1657. if ( !InsertDN( pNewQuery, pwszDN, pDeferredOU, pDeferredGPO ) ) {
  1658. xe = GetLastError();
  1659. FreeLdapQuery( pLDAP, pNewQuery );
  1660. return FALSE;
  1661. }
  1662. pNewQuery->pNext = pCurPtr;
  1663. if ( pTrailPtr == NULL )
  1664. *ppLdapQuery = pNewQuery;
  1665. else
  1666. pTrailPtr->pNext = pNewQuery;
  1667. return TRUE;
  1668. } else {
  1669. //
  1670. // Advance down the list
  1671. //
  1672. pTrailPtr = pCurPtr;
  1673. pCurPtr = pCurPtr->pNext;
  1674. }
  1675. } // while
  1676. //
  1677. // Null list or end of list case.
  1678. //
  1679. pNewQuery = AllocLdapQuery( pwszDomain );
  1680. if ( pNewQuery == NULL ) {
  1681. xe = GetLastError();
  1682. return FALSE;
  1683. }
  1684. if ( !InsertDN( pNewQuery, pwszDN, pDeferredOU, pDeferredGPO ) ) {
  1685. xe = GetLastError();
  1686. FreeLdapQuery( pLDAP, pNewQuery );
  1687. return FALSE;
  1688. }
  1689. pNewQuery->pNext = pCurPtr;
  1690. if ( pTrailPtr == NULL )
  1691. *ppLdapQuery = pNewQuery;
  1692. else
  1693. pTrailPtr->pNext = pNewQuery;
  1694. return TRUE;
  1695. }
  1696. //*************************************************************
  1697. //
  1698. // EvalList()
  1699. //
  1700. // Purpose: Encapsulates common processing functionality for
  1701. // forced and nonforced lists
  1702. //
  1703. // Parameters: pLDAP - LDAP api
  1704. // dwFlags - GetGPOList flags
  1705. // bVerbose - Verbose flag
  1706. // hToken - User or machine token
  1707. // pDeferredList - List of deferred GPOs
  1708. // ppGPOList - List of evaluated GPOs
  1709. // ppGpContainerList - List of Gp Containers
  1710. // pGpoFilter - Gpo filter
  1711. // pLocator - WMI interfaces
  1712. //
  1713. // Return: TRUE if successful
  1714. // FALSE if an error occurs
  1715. //
  1716. //*************************************************************
  1717. BOOL EvalList( PLDAP_API pLDAP,
  1718. DWORD dwFlags,
  1719. HANDLE hToken,
  1720. BOOL bVerbose,
  1721. PGROUP_POLICY_OBJECT pDeferredList,
  1722. PGROUP_POLICY_OBJECT *ppGPOList,
  1723. LPGPCONTAINER *ppGpContainerList,
  1724. PRSOPTOKEN pRsopToken,
  1725. CGpoFilter *pGpoFilter,
  1726. CLocator *pLocator )
  1727. {
  1728. PGROUP_POLICY_OBJECT pGPOTemp = pDeferredList;
  1729. while ( pGPOTemp ) {
  1730. PLDAPMessage pGPOMsg = (PLDAPMessage) pGPOTemp->lParam;
  1731. if ( pGPOMsg == NULL ) {
  1732. DebugMsg((DM_VERBOSE, TEXT("EvalList: Object <%s> cannot be accessed"),
  1733. pGPOTemp->lpDSPath ));
  1734. if (dwFlags & GP_PLANMODE) {
  1735. CEvents ev(TRUE, EVENT_OBJECT_NOT_FOUND_PLANNING);
  1736. ev.AddArg(pGPOTemp->lpDSPath); ev.Report();
  1737. }
  1738. else {
  1739. if (bVerbose) {
  1740. CEvents ev(FALSE, EVENT_OBJECT_NOT_FOUND);
  1741. ev.AddArg(pGPOTemp->lpDSPath); ev.AddArg((DWORD)0); ev.Report();
  1742. }
  1743. }
  1744. } else {
  1745. DmAssert( pGPOTemp->lParam2 != NULL );
  1746. DmAssert( ((LPGPOPROCDATA)(pGPOTemp->lParam2))->pLdapHandle != NULL );
  1747. if ( !ProcessGPO( pGPOTemp->lpDSPath,
  1748. dwFlags,
  1749. hToken,
  1750. ppGPOList,
  1751. ppGpContainerList,
  1752. pGPOTemp->dwOptions,
  1753. FALSE,
  1754. bVerbose,
  1755. pGPOTemp->GPOLink,
  1756. pGPOTemp->lpLink,
  1757. ((LPGPOPROCDATA)(pGPOTemp->lParam2))->pLdapHandle,
  1758. pLDAP,
  1759. pGPOMsg,
  1760. FALSE,
  1761. pRsopToken,
  1762. pGpoFilter,
  1763. pLocator,
  1764. ((LPGPOPROCDATA)(pGPOTemp->lParam2))->bProcessGPO ) )
  1765. {
  1766. DebugMsg((DM_WARNING, TEXT("EvalList: ProcessGPO failed") ));
  1767. return FALSE;
  1768. }
  1769. }
  1770. pGPOTemp = pGPOTemp->pNext;
  1771. }
  1772. return TRUE;
  1773. }
  1774. //*************************************************************
  1775. //
  1776. // EvaluateDeferredGPOs()
  1777. //
  1778. // Purpose: Uses a single ldap query to evaluate deferred
  1779. // GPO lists.
  1780. //
  1781. // Parameters: pldBound - Bound LDAP handle
  1782. // pLDAP - LDAP api
  1783. // pwszDomainBound - Domain already bound to
  1784. // dwFlags - GetGPOList flags
  1785. // hToken - User or machine token
  1786. // pDeferredForcedList - List of deferred forced GPOs
  1787. // pDeferredNonForcedList - List of deferred non-forced GPOs
  1788. // pGPOForcedList - List of forced GPOs
  1789. // pGPONonForcedList - List of non-forced GPOs
  1790. // ppGpContainerList - List of Gp Containers
  1791. // pGpoFilter - Gpo filter
  1792. // pLocator - WMI interfaces
  1793. //
  1794. // Return: TRUE if successful
  1795. // FALSE if an error occurs
  1796. //
  1797. //*************************************************************
  1798. BOOL EvaluateDeferredGPOs (PLDAP pldBound,
  1799. PLDAP_API pLDAP,
  1800. LPTSTR pwszDomainBound,
  1801. DWORD dwFlags,
  1802. HANDLE hToken,
  1803. BOOL bVerbose,
  1804. PGROUP_POLICY_OBJECT pDeferredForcedList,
  1805. PGROUP_POLICY_OBJECT pDeferredNonForcedList,
  1806. PGROUP_POLICY_OBJECT *ppForcedList,
  1807. PGROUP_POLICY_OBJECT *ppNonForcedList,
  1808. LPGPCONTAINER *ppGpContainerList,
  1809. PRSOPTOKEN pRsopToken,
  1810. CGpoFilter *pGpoFilter,
  1811. CLocator *pLocator )
  1812. {
  1813. ULONG ulResult;
  1814. BOOL bResult = FALSE;
  1815. BYTE berValue[8];
  1816. LDAPControl SeInfoControl = { LDAP_SERVER_SD_FLAGS_OID_W, { 5, (PCHAR)berValue }, TRUE };
  1817. LDAPControl referralControl = { LDAP_SERVER_DOMAIN_SCOPE_OID_W, { 0, NULL}, TRUE };
  1818. PLDAPControl ServerControls[] = { &SeInfoControl, &referralControl, NULL };
  1819. TCHAR szSDProperty[] = TEXT("nTSecurityDescriptor");
  1820. TCHAR szCommonName[] = TEXT("cn");
  1821. TCHAR szDisplayName[] = TEXT("displayName");
  1822. TCHAR szFileSysPath[] = TEXT("gPCFileSysPath");
  1823. TCHAR szVersion[] = TEXT("versionNumber");
  1824. TCHAR szFunctionalityVersion[] = GPO_FUNCTIONALITY_VERSION;
  1825. TCHAR szFlags[] = TEXT("flags");
  1826. TCHAR szWmiFilter[] = TEXT("gPCWQLFilter");
  1827. PWSTR rgAttribs[12] = {szSDProperty,
  1828. szFileSysPath,
  1829. szCommonName,
  1830. szDisplayName,
  1831. szVersion,
  1832. szFunctionalityVersion,
  1833. szFlags,
  1834. GPO_MACHEXTENSION_NAMES,
  1835. GPO_USEREXTENSION_NAMES,
  1836. szObjectClass,
  1837. szWmiFilter,
  1838. NULL };
  1839. PGROUP_POLICY_OBJECT pGPOTemp = pDeferredForcedList;
  1840. LDAPQUERY *pLdapQuery = NULL, *pQuery = NULL;
  1841. VOID *pData;
  1842. PDS_API pdsApi;
  1843. BOOL bRsopPlanningMode = (pRsopToken != 0);
  1844. BOOL bConfigContainer = FALSE;
  1845. *ppForcedList = NULL;
  1846. *ppNonForcedList = NULL;
  1847. XLastError xe;
  1848. if ( pDeferredForcedList == NULL && pDeferredNonForcedList == NULL )
  1849. return TRUE;
  1850. //
  1851. // Demand load ntdsapi.dll
  1852. //
  1853. pdsApi = LoadDSApi();
  1854. if ( pdsApi == 0 ) {
  1855. xe = GetLastError();
  1856. DebugMsg((DM_WARNING, TEXT("EvaluateDeferredGpos: Failed to load ntdsapi.dll")));
  1857. goto Exit;
  1858. }
  1859. while ( pGPOTemp ) {
  1860. if ( !AddDN( pLDAP, &pLdapQuery, pGPOTemp->lpDSPath, NULL, pGPOTemp ) ) {
  1861. xe = GetLastError();
  1862. goto Exit;
  1863. }
  1864. pGPOTemp = pGPOTemp->pNext;
  1865. }
  1866. pGPOTemp = pDeferredNonForcedList;
  1867. while ( pGPOTemp ) {
  1868. if ( !AddDN( pLDAP, &pLdapQuery, pGPOTemp->lpDSPath, NULL, pGPOTemp ) ) {
  1869. xe = GetLastError();
  1870. goto Exit;
  1871. }
  1872. pGPOTemp = pGPOTemp->pNext;
  1873. }
  1874. //
  1875. // Setup the BER encoding
  1876. //
  1877. berValue[0] = 0x30;
  1878. berValue[1] = 0x03;
  1879. berValue[2] = 0x02; // denotes an integer
  1880. berValue[3] = 0x01; // denotes size
  1881. berValue[4] = (BYTE)((DACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION) & 0xF);
  1882. pQuery = pLdapQuery;
  1883. while ( pQuery ) {
  1884. //
  1885. // The check below needs to be more sophisticated to take care
  1886. // of spaces in names etc.
  1887. //
  1888. // It is assumed that the configuration
  1889. // container would be common across the whole forest and will
  1890. // not need a new bind..
  1891. //
  1892. if (CompareString ( LOCALE_INVARIANT, NORM_IGNORECASE,
  1893. pQuery->pwszDomain, 16, TEXT("cn=configuration"), 16) == CSTR_EQUAL ) {
  1894. DebugMsg((DM_VERBOSE, TEXT("EvaluateDeferredGPOs: DN %s is under cn=configuration container"), pQuery->pwszDomain ));
  1895. bConfigContainer = TRUE;
  1896. }
  1897. else
  1898. bConfigContainer = FALSE;
  1899. //
  1900. // Check if this is a cross-domain Gpo and hence needs a new bind
  1901. //
  1902. WCHAR *pDomainString[1];
  1903. PDS_NAME_RESULT pNameResult = NULL;
  1904. PLDAP pLdapHandle = NULL;
  1905. if (!bConfigContainer)
  1906. pDomainString[0] = pQuery->pwszDomain;
  1907. else {
  1908. DebugMsg((DM_VERBOSE, TEXT("EvaluateDeferredGPOs: The GPO is under the config container. Querying seperately\n")));
  1909. //
  1910. // This is a configuration container and we have to figure
  1911. // out the domain name still..
  1912. //
  1913. LPTSTR pwszTemp = pQuery->pwszDomain;
  1914. pDomainString[0] = NULL;
  1915. while ( *pwszTemp ) {
  1916. if (CompareString ( LOCALE_INVARIANT, NORM_IGNORECASE,
  1917. pwszTemp, 3, TEXT("DC="), 3) == CSTR_EQUAL ) {
  1918. pDomainString[0] = pwszTemp;
  1919. break;
  1920. }
  1921. //
  1922. // Move to the next chunk of the DN name
  1923. //
  1924. while ( *pwszTemp && (*pwszTemp != TEXT(',')))
  1925. pwszTemp++;
  1926. if ( *pwszTemp == TEXT(','))
  1927. pwszTemp++;
  1928. }
  1929. if ( pDomainString[0] == NULL ) {
  1930. xe = ERROR_INVALID_DATA;
  1931. DebugMsg((DM_WARNING, TEXT("EvaluateDeferredGPOs: Domain not found for <%s>. Exiting."), pQuery->pwszDomain ));
  1932. goto Exit;
  1933. }
  1934. }
  1935. ulResult = pdsApi->pfnDsCrackNames( (HANDLE) -1,
  1936. DS_NAME_FLAG_SYNTACTICAL_ONLY,
  1937. DS_FQDN_1779_NAME,
  1938. DS_CANONICAL_NAME,
  1939. 1,
  1940. pDomainString,
  1941. &pNameResult );
  1942. if ( ulResult != ERROR_SUCCESS
  1943. || pNameResult->cItems == 0
  1944. || pNameResult->rItems[0].status != ERROR_SUCCESS
  1945. || pNameResult->rItems[0].pDomain == NULL ) {
  1946. xe = ulResult;
  1947. DebugMsg((DM_VERBOSE, TEXT("EvaluateDeferredGPOs: DsCrackNames failed with 0x%x."), ulResult ));
  1948. goto Exit;
  1949. }
  1950. //
  1951. // Optimize same domain Gpo queries by not doing an unnecessary bind
  1952. //
  1953. pQuery->pLdapHandle = pldBound;
  1954. if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE,
  1955. pwszDomainBound, -1, pNameResult->rItems[0].pDomain, -1) != CSTR_EQUAL) {
  1956. //
  1957. // Cross-domain Gpo query and so need to bind to new domain
  1958. //
  1959. DebugMsg((DM_VERBOSE, TEXT("EvaluateDeferredGPOs: Doing an ldap bind to cross-domain <%s>"),
  1960. pNameResult->rItems[0].pDomain));
  1961. pLdapHandle = pLDAP->pfnldap_init( pNameResult->rItems[0].pDomain, LDAP_PORT);
  1962. if (!pLdapHandle) {
  1963. xe = pLDAP->pfnLdapMapErrorToWin32(pLDAP->pfnLdapGetLastError());
  1964. DebugMsg((DM_WARNING, TEXT("EvaluateDeferredGPOs: ldap_init for <%s> failed with = 0x%x or %d"),
  1965. pNameResult->rItems[0].pDomain, pLDAP->pfnLdapGetLastError(), GetLastError()));
  1966. CEvents ev(TRUE, EVENT_FAILED_DS_INIT);
  1967. ev.AddArg(pNameResult->rItems[0].pDomain); ev.AddArgLdapError(pLDAP->pfnLdapGetLastError()); ev.Report();
  1968. pdsApi->pfnDsFreeNameResult( pNameResult );
  1969. goto Exit;
  1970. }
  1971. //
  1972. // Turn on Packet integrity flag
  1973. //
  1974. pData = (VOID *) LDAP_OPT_ON;
  1975. ulResult = pLDAP->pfnldap_set_option(pLdapHandle, LDAP_OPT_SIGN, &pData);
  1976. if (ulResult != LDAP_SUCCESS) {
  1977. xe = pLDAP->pfnLdapMapErrorToWin32(ulResult);
  1978. DebugMsg((DM_WARNING, TEXT("EvaluateDeferredGPOs: Failed to turn on LDAP_OPT_SIGN with %d"), ulResult));
  1979. pdsApi->pfnDsFreeNameResult( pNameResult );
  1980. pLDAP->pfnldap_unbind(pLdapHandle);
  1981. pLdapHandle = 0;
  1982. goto Exit;
  1983. }
  1984. ulResult = pLDAP->pfnldap_connect(pLdapHandle, 0);
  1985. if (ulResult != LDAP_SUCCESS) {
  1986. CEvents ev(TRUE, EVENT_FAILED_DS_CONNECT);
  1987. ev.AddArg(pNameResult->rItems[0].pDomain); ev.AddArgLdapError(ulResult); ev.Report();
  1988. xe = pLDAP->pfnLdapMapErrorToWin32(ulResult);
  1989. DebugMsg((DM_WARNING, TEXT("EvaluateDeferredGPOs: Failed to connect with %d"), ulResult));
  1990. pdsApi->pfnDsFreeNameResult( pNameResult );
  1991. pLDAP->pfnldap_unbind(pLdapHandle);
  1992. pLdapHandle = 0;
  1993. goto Exit;
  1994. }
  1995. //
  1996. // Transfer ownerhip of ldap handle to pQuery struct
  1997. //
  1998. pQuery->pLdapHandle = pLdapHandle;
  1999. pQuery->bOwnLdapHandle = TRUE;
  2000. if ( !bRsopPlanningMode && (dwFlags & GPO_LIST_FLAG_MACHINE) ) {
  2001. //
  2002. // For machine policies specifically ask for Kerberos as the only authentication
  2003. // mechanism. Otherwise if Kerberos were to fail for some reason, then NTLM is used
  2004. // and localsystem context has no real credentials, which means that we won't get
  2005. // any GPOs back.
  2006. //
  2007. SEC_WINNT_AUTH_IDENTITY_EXW secIdentity;
  2008. secIdentity.Version = SEC_WINNT_AUTH_IDENTITY_VERSION;
  2009. secIdentity.Length = sizeof(SEC_WINNT_AUTH_IDENTITY_EXW);
  2010. secIdentity.User = 0;
  2011. secIdentity.UserLength = 0;
  2012. secIdentity.Domain = 0;
  2013. secIdentity.DomainLength = 0;
  2014. secIdentity.Password = 0;
  2015. secIdentity.PasswordLength = 0;
  2016. secIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
  2017. secIdentity.PackageList = wszKerberos;
  2018. secIdentity.PackageListLength = lstrlen( wszKerberos );
  2019. ulResult = pLDAP->pfnldap_bind_s (pLdapHandle, NULL, (WCHAR *)&secIdentity, LDAP_AUTH_SSPI);
  2020. } else
  2021. ulResult = pLDAP->pfnldap_bind_s (pLdapHandle, NULL, NULL, LDAP_AUTH_SSPI);
  2022. if (ulResult != LDAP_SUCCESS) {
  2023. xe = pLDAP->pfnLdapMapErrorToWin32(ulResult);
  2024. DebugMsg((DM_WARNING, TEXT("EvaluateDeferredGPOs: ldap_bind_s failed with = <%d>"),
  2025. ulResult));
  2026. CEvents ev(TRUE, EVENT_FAILED_DS_BIND);
  2027. ev.AddArg(pNameResult->rItems[0].pDomain); ev.AddArgLdapError(ulResult); ev.Report();
  2028. pdsApi->pfnDsFreeNameResult( pNameResult );
  2029. goto Exit;
  2030. }
  2031. DebugMsg((DM_VERBOSE, TEXT("EvaluateDeferredGPOs: Bind sucessful")));
  2032. }
  2033. pdsApi->pfnDsFreeNameResult( pNameResult );
  2034. //
  2035. // Turn referrals off because this is a single domain call
  2036. //
  2037. pData = (VOID *) LDAP_OPT_OFF;
  2038. ulResult = pLDAP->pfnldap_set_option( pQuery->pLdapHandle, LDAP_OPT_REFERRALS, &pData );
  2039. if ( ulResult != LDAP_SUCCESS )
  2040. {
  2041. xe = pLDAP->pfnLdapMapErrorToWin32(ulResult);
  2042. DebugMsg((DM_WARNING, TEXT("EvalauteDeferredGPOs: Failed to turn off referrals with error %d"), ulResult));
  2043. goto Exit;
  2044. }
  2045. //
  2046. // Search for GPOs
  2047. //
  2048. //
  2049. // restrict the search to just the policies container
  2050. //
  2051. DmAssert( pQuery->pwszDomain != NULL && pQuery->pwszFilter != NULL );
  2052. XPtrLF<WCHAR> xszGPOSearchBase;
  2053. DWORD cChLen;
  2054. cChLen = (1+lstrlen(pQuery->pwszDomain)+lstrlen(DOMAIN_GPO_LOCATION_FMT));
  2055. xszGPOSearchBase = (LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR)*cChLen);
  2056. if (!xszGPOSearchBase)
  2057. {
  2058. xe = GetLastError();
  2059. DebugMsg((DM_WARNING, TEXT("EvalauteDeferredGPOs: Failed to allocate memory for GPO base search with %d"), GetLastError()));
  2060. goto Exit;
  2061. }
  2062. HRESULT hr;
  2063. hr = StringCchPrintf(xszGPOSearchBase, cChLen,
  2064. DOMAIN_GPO_LOCATION_FMT,
  2065. pQuery->pwszDomain);
  2066. DmAssert(SUCCEEDED(hr));
  2067. DebugMsg((DM_VERBOSE, TEXT("EvaluateDeferredGPOs: Searching for GPOs in %s"), (LPWSTR)xszGPOSearchBase));
  2068. ulResult = pLDAP->pfnldap_search_ext_s(pQuery->pLdapHandle,
  2069. (LPWSTR)xszGPOSearchBase,
  2070. LDAP_SCOPE_SUBTREE,
  2071. pQuery->pwszFilter, rgAttribs, 0,
  2072. (PLDAPControl*)ServerControls,
  2073. NULL, NULL, 0x10000, &pQuery->pMessage);
  2074. //
  2075. // If the search fails, store the error code and return
  2076. //
  2077. if (ulResult != LDAP_SUCCESS) {
  2078. if (ulResult == LDAP_NO_SUCH_ATTRIBUTE) {
  2079. DebugMsg((DM_VERBOSE, TEXT("EvaluateDeferredGPOs: All objects can not be accessed.")));
  2080. if (dwFlags & GP_PLANMODE) {
  2081. CEvents ev(TRUE, EVENT_NO_GPOS2_PLANNING); ev.Report();
  2082. }
  2083. else {
  2084. if (bVerbose) {
  2085. CEvents ev(FALSE, EVENT_NO_GPOS2); ev.Report();
  2086. }
  2087. }
  2088. bResult = TRUE;
  2089. } else if (ulResult == LDAP_NO_SUCH_OBJECT) {
  2090. DebugMsg((DM_VERBOSE, TEXT("EvalateDeferredGPOs: Objects do not exist.") ));
  2091. if (dwFlags & GP_PLANMODE) {
  2092. // Same error or different
  2093. CEvents ev(TRUE, EVENT_NO_GPOS2_PLANNING); ev.Report();
  2094. }
  2095. else {
  2096. if (bVerbose) {
  2097. CEvents ev(FALSE, EVENT_NO_GPOS2); ev.Report();
  2098. }
  2099. }
  2100. bResult = TRUE;
  2101. } else if (ulResult == LDAP_SIZELIMIT_EXCEEDED) {
  2102. xe = pLDAP->pfnLdapMapErrorToWin32(ulResult);
  2103. DebugMsg((DM_WARNING, TEXT("EvalateDeferredGPOs: Too many GPOs in search.") ));
  2104. CEvents ev(TRUE, EVENT_TOO_MANY_GPOS); ev.Report();
  2105. } else {
  2106. xe = pLDAP->pfnLdapMapErrorToWin32(ulResult);
  2107. DebugMsg((DM_WARNING, TEXT("EvaluteDeferredGPOs: Failed to search with error 0x%x"), ulResult));
  2108. CEvents ev(TRUE, EVENT_FAILED_GPO_SEARCH);
  2109. ev.AddArgLdapError(ulResult); ev.Report();
  2110. }
  2111. goto Exit;
  2112. }
  2113. //
  2114. // If the search succeeds, but the message is empty,
  2115. // store the error code and return
  2116. //
  2117. if ( pQuery->pMessage == NULL ) {
  2118. xe = pLDAP->pfnLdapMapErrorToWin32(pQuery->pLdapHandle->ld_errno);
  2119. DebugMsg((DM_WARNING, TEXT("EvaluateDeferredGPOs: Search returned an empty message structure. Error = 0x%x"),
  2120. pQuery->pLdapHandle->ld_errno));
  2121. goto Exit;
  2122. }
  2123. if ( !MatchDnWithDeferredItems( pLDAP, pQuery, FALSE ) ) {
  2124. xe = GetLastError();
  2125. goto Exit;
  2126. }
  2127. pQuery = pQuery->pNext;
  2128. } // while
  2129. if ( !EvalList( pLDAP, dwFlags, hToken, bVerbose,
  2130. pDeferredForcedList, ppForcedList, ppGpContainerList, pRsopToken, pGpoFilter, pLocator ) ) {
  2131. xe = GetLastError();
  2132. goto Exit;
  2133. }
  2134. if ( !EvalList( pLDAP, dwFlags, hToken, bVerbose,
  2135. pDeferredNonForcedList, ppNonForcedList, ppGpContainerList, pRsopToken, pGpoFilter, pLocator ) ) {
  2136. xe = GetLastError();
  2137. goto Exit;
  2138. }
  2139. bResult = TRUE;
  2140. Exit:
  2141. //
  2142. // Free all resources except for ppForcedList, ppNonForcedList
  2143. // which are owned by caller.
  2144. //
  2145. while ( pLdapQuery ) {
  2146. pQuery = pLdapQuery->pNext;
  2147. FreeLdapQuery( pLDAP, pLdapQuery );
  2148. pLdapQuery = pQuery;
  2149. }
  2150. return bResult;
  2151. }
  2152. //*************************************************************
  2153. //
  2154. // AddOU()
  2155. //
  2156. // Purpose: Appends an OU or domain to deferred list.
  2157. //
  2158. // Parameters: ppOUList - OU list to append to
  2159. // pwszOU - OU name
  2160. // gpoLink - Type of Gpo
  2161. //
  2162. // Return: TRUE if successful
  2163. // FALSE if an error occurs
  2164. //
  2165. //*************************************************************
  2166. BOOL AddOU( DNENTRY **ppOUList, LPTSTR pwszOU, GPO_LINK gpoLink )
  2167. {
  2168. DNENTRY *pOUTemp = *ppOUList;
  2169. DNENTRY *pOULast = NULL;
  2170. DNENTRY *pOUNew = AllocDnEntry( pwszOU );
  2171. if ( pOUNew == NULL ) {
  2172. return FALSE;
  2173. }
  2174. pOUNew->gpoLink = gpoLink;
  2175. while ( pOUTemp ) {
  2176. pOULast = pOUTemp;
  2177. pOUTemp = pOUTemp->pNext;
  2178. }
  2179. if ( pOULast )
  2180. pOULast->pNext = pOUNew;
  2181. else
  2182. *ppOUList = pOUNew;
  2183. return TRUE;
  2184. }
  2185. //*************************************************************
  2186. //
  2187. // EvaluateDeferredOUs()
  2188. //
  2189. // Purpose: Uses a single Ldap query to evaluate all OUs
  2190. //
  2191. // Parameters: ppOUList - OU list to append to
  2192. // dwFlags - GetGPOList flags
  2193. // pGPOForcedList - List of forced GPOs
  2194. // pGPONonForcedList - List of non-forced GPOs
  2195. // ppSOMList - List of LSDOUs
  2196. // ppGpContainerList - List of Gp Containers
  2197. // bVerbose - Verbose output
  2198. // pld - LDAP info
  2199. // pLDAP - LDAP api
  2200. // pLDAPMsg - LDAP message
  2201. // bBlock - Pointer to the block flag
  2202. // hToken - User / machine token
  2203. //
  2204. // Return: TRUE if successful
  2205. // FALSE if an error occurs
  2206. //
  2207. //*************************************************************
  2208. BOOL EvaluateDeferredOUs( DNENTRY *pOUList,
  2209. DWORD dwFlags,
  2210. HANDLE hToken,
  2211. PGROUP_POLICY_OBJECT *ppDeferredForcedList,
  2212. PGROUP_POLICY_OBJECT *ppDeferredNonForcedList,
  2213. LPSCOPEOFMGMT *ppSOMList,
  2214. LPGPCONTAINER *ppGpContainerList,
  2215. BOOL bVerbose,
  2216. PLDAP pld,
  2217. PLDAP_API pLDAP,
  2218. BOOL *pbBlock,
  2219. PRSOPTOKEN pRsopToken)
  2220. {
  2221. ULONG ulResult;
  2222. BOOL bResult = FALSE;
  2223. LDAPQUERY *pLdapQuery = NULL;
  2224. BYTE berValue[8];
  2225. LDAPControl SeInfoControl = { LDAP_SERVER_SD_FLAGS_OID_W, { 5, (PCHAR)berValue }, TRUE };
  2226. PLDAPControl ServerControls[] = { &SeInfoControl, NULL };
  2227. TCHAR szGPLink[] = TEXT("gPLink");
  2228. TCHAR szGPOptions[] = TEXT("gPOptions");
  2229. TCHAR szSDProperty[] = TEXT("nTSecurityDescriptor");
  2230. LPTSTR lpAttr[] = { szGPLink,
  2231. szGPOptions,
  2232. szSDProperty,
  2233. NULL
  2234. };
  2235. DNENTRY *pOUTemp = pOUList;
  2236. VOID *pData;
  2237. XLastError xe;
  2238. //
  2239. // Setup the BER encoding for the SD
  2240. //
  2241. berValue[0] = 0x30;
  2242. berValue[1] = 0x03;
  2243. berValue[2] = 0x02; // denotes an integer
  2244. berValue[3] = 0x01; // denotes size
  2245. berValue[4] = (BYTE)((DACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION) & 0xF);
  2246. if ( !pRsopToken )
  2247. {
  2248. //
  2249. // if it is not planning mode, don't get the SD
  2250. //
  2251. lpAttr[2] = NULL;
  2252. ServerControls[0] = NULL;
  2253. }
  2254. if ( pOUTemp == NULL )
  2255. return TRUE;
  2256. while ( pOUTemp ) {
  2257. if ( !AddDN( pLDAP, &pLdapQuery, pOUTemp->pwszDN, pOUTemp, NULL ) ) {
  2258. xe = GetLastError();
  2259. goto Exit;
  2260. }
  2261. pOUTemp = pOUTemp->pNext;
  2262. }
  2263. pLdapQuery->pLdapHandle = pld;
  2264. //
  2265. // Turn referrals off because this is a single domain call
  2266. //
  2267. if ( !pRsopToken )
  2268. {
  2269. pData = (VOID *) LDAP_OPT_OFF;
  2270. ulResult = pLDAP->pfnldap_set_option( pLdapQuery->pLdapHandle, LDAP_OPT_REFERRALS, &pData );
  2271. if ( ulResult != LDAP_SUCCESS ) {
  2272. xe = pLDAP->pfnLdapMapErrorToWin32(ulResult);
  2273. DebugMsg((DM_WARNING, TEXT("EvaluteDeferredOUs: Failed to turn off referrals with error %d"), ulResult));
  2274. goto Exit;
  2275. }
  2276. }
  2277. ulResult = pLDAP->pfnldap_search_ext_s(pld, pLdapQuery->pwszDomain, LDAP_SCOPE_SUBTREE,
  2278. pLdapQuery->pwszFilter, lpAttr, FALSE,
  2279. (PLDAPControl*)ServerControls,
  2280. NULL, NULL, 0, &pLdapQuery->pMessage);
  2281. //
  2282. // If the search fails, store the error code and return
  2283. //
  2284. if (ulResult != LDAP_SUCCESS) {
  2285. if (ulResult == LDAP_NO_SUCH_ATTRIBUTE) {
  2286. DebugMsg((DM_VERBOSE, TEXT("EvaluateDeferredOUs: All objects can not be accessed.")));
  2287. bResult = TRUE;
  2288. } else if (ulResult == LDAP_NO_SUCH_OBJECT) {
  2289. DebugMsg((DM_VERBOSE, TEXT("EvalateDeferredOUs: Objects do not exist.") ));
  2290. bResult = TRUE;
  2291. } else if (ulResult == LDAP_SIZELIMIT_EXCEEDED) {
  2292. xe = pLDAP->pfnLdapMapErrorToWin32(ulResult);
  2293. DebugMsg((DM_WARNING, TEXT("EvalateDeferredOUs: Too many linked GPOs in search.") ));
  2294. CEvents ev(TRUE, EVENT_TOO_MANY_GPOS); ev.Report();
  2295. } else {
  2296. xe = pLDAP->pfnLdapMapErrorToWin32(ulResult);
  2297. DebugMsg((DM_WARNING, TEXT("EvaluateDeferredOUs: Failed to search with error %d"), ulResult));
  2298. CEvents ev(TRUE, EVENT_FAILED_OU_SEARCH);
  2299. ev.AddArg(ulResult); ev.Report();
  2300. }
  2301. goto Exit;
  2302. }
  2303. //
  2304. // If the search succeeds, but the message is empty,
  2305. // store the error code and return
  2306. //
  2307. if ( pLdapQuery->pMessage == NULL ) {
  2308. xe = pLDAP->pfnLdapMapErrorToWin32(pld->ld_errno);
  2309. DebugMsg((DM_WARNING, TEXT("EvaluateDeferredOUs: Search returned an empty message structure. Error = %d"),
  2310. pld->ld_errno));
  2311. goto Exit;
  2312. }
  2313. if ( !MatchDnWithDeferredItems( pLDAP, pLdapQuery, TRUE ) ) {
  2314. xe = GetLastError();
  2315. goto Exit;
  2316. }
  2317. //
  2318. // Evaluate the OU list
  2319. //
  2320. pOUTemp = pOUList;
  2321. while ( pOUTemp ) {
  2322. PLDAPMessage pOUMsg = pOUTemp->pOUMsg;
  2323. if ( pOUMsg == NULL ) {
  2324. xe = ERROR_INVALID_DATA;
  2325. DebugMsg((DM_WARNING, TEXT("EvaluateDeferredOUs: Object <%s> cannot be accessed"),
  2326. pOUTemp->pwszDN ));
  2327. CEvents ev(TRUE, EVENT_OU_NOTFOUND);
  2328. ev.AddArg(pOUTemp->pwszDN); ev.Report();
  2329. goto Exit;
  2330. } else {
  2331. if ( !SearchDSObject( pOUTemp->pwszDN, dwFlags, hToken, ppDeferredForcedList, ppDeferredNonForcedList,
  2332. ppSOMList, ppGpContainerList,
  2333. bVerbose, pOUTemp->gpoLink, pld, pLDAP, pOUMsg, pbBlock, pRsopToken)) {
  2334. xe = GetLastError();
  2335. DebugMsg((DM_WARNING, TEXT("EvaluateDeferredOUs: SearchDSObject failed") ));
  2336. goto Exit;
  2337. }
  2338. }
  2339. pOUTemp = pOUTemp->pNext;
  2340. }
  2341. bResult = TRUE;
  2342. Exit:
  2343. while ( pLdapQuery ) {
  2344. LDAPQUERY *pQuery = pLdapQuery->pNext;
  2345. FreeLdapQuery( pLDAP, pLdapQuery );
  2346. pLdapQuery = pQuery;
  2347. }
  2348. return bResult;
  2349. }
  2350. //*************************************************************
  2351. //
  2352. // GetMachineDomainDS()
  2353. //
  2354. // Purpose: Obtain the machine domain DS
  2355. //
  2356. // Parameters: pNetApi32 - netapi32.dll
  2357. // pLdapApi - wldap32.dll
  2358. //
  2359. // Return: valid PLDAP if successful
  2360. // 0 if an error occurs
  2361. //
  2362. //*************************************************************
  2363. PLDAP
  2364. GetMachineDomainDS( PNETAPI32_API pNetApi32, PLDAP_API pLdapApi )
  2365. {
  2366. PLDAP pld = 0;
  2367. DWORD dwResult = 0;
  2368. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pDsInfo = NULL;
  2369. ULONG ulResult;
  2370. VOID *pData;
  2371. XLastError xe;
  2372. //
  2373. // get the machine domain name
  2374. //
  2375. dwResult = pNetApi32->pfnDsRoleGetPrimaryDomainInformation( NULL,
  2376. DsRolePrimaryDomainInfoBasic,
  2377. (PBYTE *)&pDsInfo );
  2378. if ( dwResult == ERROR_SUCCESS )
  2379. {
  2380. SEC_WINNT_AUTH_IDENTITY_EXW secIdentity;
  2381. pld = pLdapApi->pfnldap_init( pDsInfo->DomainNameDns, LDAP_PORT );
  2382. if (!pld) {
  2383. xe = pLdapApi->pfnLdapMapErrorToWin32(pLdapApi->pfnLdapGetLastError());
  2384. DebugMsg((DM_WARNING, TEXT("GetMachineDomainDS: ldap_open for <%s> failed with = 0x%x or %d"),
  2385. pDsInfo->DomainNameDns, pLdapApi->pfnLdapGetLastError(), GetLastError()));
  2386. return pld;
  2387. }
  2388. //
  2389. // Turn on Packet integrity flag
  2390. //
  2391. pData = (VOID *) LDAP_OPT_ON;
  2392. ulResult = pLdapApi->pfnldap_set_option(pld, LDAP_OPT_SIGN, &pData);
  2393. if (ulResult != LDAP_SUCCESS) {
  2394. xe = pLdapApi->pfnLdapMapErrorToWin32(ulResult);
  2395. DebugMsg((DM_WARNING, TEXT("GetMachineDomainDS: Failed to turn on LDAP_OPT_SIGN with %d"), ulResult));
  2396. pLdapApi->pfnldap_unbind(pld);
  2397. pld = 0;
  2398. return pld;
  2399. }
  2400. ulResult = pLdapApi->pfnldap_connect(pld, 0);
  2401. if (ulResult != LDAP_SUCCESS) {
  2402. xe = pLdapApi->pfnLdapMapErrorToWin32(ulResult);
  2403. DebugMsg((DM_WARNING, TEXT("GetMachineDomainDS: Failed to connect with %d"), ulResult));
  2404. pLdapApi->pfnldap_unbind(pld);
  2405. pld = 0;
  2406. return pld;
  2407. }
  2408. //
  2409. // For machine policies specifically ask for Kerberos as the only authentication
  2410. // mechanism. Otherwise if Kerberos were to fail for some reason, then NTLM is used
  2411. // and localsystem context has no real credentials, which means that we won't get
  2412. // any GPOs back.
  2413. //
  2414. secIdentity.Version = SEC_WINNT_AUTH_IDENTITY_VERSION;
  2415. secIdentity.Length = sizeof(SEC_WINNT_AUTH_IDENTITY_EXW);
  2416. secIdentity.User = 0;
  2417. secIdentity.UserLength = 0;
  2418. secIdentity.Domain = 0;
  2419. secIdentity.DomainLength = 0;
  2420. secIdentity.Password = 0;
  2421. secIdentity.PasswordLength = 0;
  2422. secIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
  2423. secIdentity.PackageList = wszKerberos;
  2424. secIdentity.PackageListLength = lstrlen( wszKerberos );
  2425. if ( (ulResult = pLdapApi->pfnldap_bind_s (pld, 0, (WCHAR *)&secIdentity, LDAP_AUTH_SSPI)) != LDAP_SUCCESS )
  2426. {
  2427. DebugMsg((DM_WARNING, TEXT("GetMachineDomainDS: ldap_bind_s failed with %d"), ulResult));
  2428. xe = pLdapApi->pfnLdapMapErrorToWin32(ulResult);
  2429. pLdapApi->pfnldap_unbind(pld);
  2430. pld = 0;
  2431. }
  2432. pNetApi32->pfnDsRoleFreeMemory( pDsInfo );
  2433. }
  2434. else
  2435. {
  2436. xe = dwResult;
  2437. DebugMsg((DM_WARNING, TEXT("GetMachineDomainDS: The domain does not have a DS")));
  2438. }
  2439. return pld;
  2440. }
  2441. //*************************************************************
  2442. //
  2443. // AllocSOM()
  2444. //
  2445. // Purpose: Allocates a new struct for SOM
  2446. //
  2447. //
  2448. // Parameters: pwszSOMId - Name of SOM
  2449. //
  2450. // Return: Pointer if successful
  2451. // NULL if an error occurs
  2452. //
  2453. //*************************************************************
  2454. SCOPEOFMGMT *AllocSOM( LPWSTR pwszSOMId )
  2455. {
  2456. XLastError xe;
  2457. HRESULT hr = S_OK;
  2458. SCOPEOFMGMT *pSOM = (SCOPEOFMGMT *) LocalAlloc( LPTR, sizeof(SCOPEOFMGMT) );
  2459. if ( pSOM == NULL ) {
  2460. xe = GetLastError();
  2461. return NULL;
  2462. }
  2463. pSOM->pwszSOMId = (LPWSTR) LocalAlloc( LPTR, (lstrlen(pwszSOMId) + 1) * sizeof(WCHAR) );
  2464. if ( pSOM->pwszSOMId == NULL ) {
  2465. xe = GetLastError();
  2466. LocalFree( pSOM );
  2467. return NULL;
  2468. }
  2469. hr = StringCchCopy( pSOM->pwszSOMId, lstrlen(pwszSOMId) + 1, pwszSOMId );
  2470. ASSERT(SUCCEEDED(hr));
  2471. return pSOM;
  2472. }
  2473. //*************************************************************
  2474. //
  2475. // FreeSOM()
  2476. //
  2477. // Purpose: Frees SOM struct
  2478. //
  2479. // Parameters: pSOM - SOM to free
  2480. //
  2481. //*************************************************************
  2482. void FreeSOM( SCOPEOFMGMT *pSOM )
  2483. {
  2484. GPLINK *pGpLink = NULL;
  2485. if ( pSOM ) {
  2486. LocalFree( pSOM->pwszSOMId );
  2487. pGpLink = pSOM->pGpLinkList;
  2488. while ( pGpLink ) {
  2489. GPLINK *pTemp = pGpLink->pNext;
  2490. FreeGpLink( pGpLink );
  2491. pGpLink = pTemp;
  2492. }
  2493. LocalFree( pSOM );
  2494. }
  2495. }
  2496. //*************************************************************
  2497. //
  2498. // AllocGpLink()
  2499. //
  2500. // Purpose: Allocates a new struct for GpLink
  2501. //
  2502. //
  2503. // Parameters: pwszGPO - Name of GPO
  2504. //
  2505. // Return: Pointer if successful
  2506. // NULL if an error occurs
  2507. //
  2508. //*************************************************************
  2509. GPLINK *AllocGpLink( LPWSTR pwszGPO, DWORD dwOptions )
  2510. {
  2511. //
  2512. // Strip out "LDAP://" prefix to get canonical Gpo path
  2513. //
  2514. WCHAR wszPrefix[] = TEXT("LDAP://");
  2515. INT iPrefixLen = lstrlen( wszPrefix );
  2516. WCHAR *pwszPath = pwszGPO;
  2517. GPLINK *pGpLink = NULL;
  2518. XLastError xe;
  2519. HRESULT hr = S_OK;
  2520. if ( (lstrlen(pwszGPO) > iPrefixLen)
  2521. && CompareString( LOCALE_INVARIANT, NORM_IGNORECASE,
  2522. pwszGPO, iPrefixLen, wszPrefix, iPrefixLen ) == CSTR_EQUAL ) {
  2523. pwszPath = pwszGPO + iPrefixLen;
  2524. }
  2525. pGpLink = (GPLINK *) LocalAlloc( LPTR, sizeof(GPLINK) );
  2526. if ( pGpLink == NULL ) {
  2527. xe = GetLastError();
  2528. return NULL;
  2529. }
  2530. pGpLink->pwszGPO = (LPWSTR) LocalAlloc( LPTR, (lstrlen(pwszPath) + 1) * sizeof(WCHAR) );
  2531. if ( pGpLink->pwszGPO == NULL ) {
  2532. xe = GetLastError();
  2533. LocalFree( pGpLink );
  2534. return NULL;
  2535. }
  2536. hr = StringCchCopy( pGpLink->pwszGPO, lstrlen(pwszPath) + 1, pwszPath );
  2537. ASSERT(SUCCEEDED(hr));
  2538. pGpLink->bEnabled = (dwOptions & GPO_FLAG_DISABLE) ? FALSE : TRUE;
  2539. if ( dwOptions & GPO_FLAG_FORCE )
  2540. pGpLink->bNoOverride = TRUE;
  2541. return pGpLink;
  2542. }
  2543. //*************************************************************
  2544. //
  2545. // FreeGpLink()
  2546. //
  2547. // Purpose: Frees GpLink struct
  2548. //
  2549. // Parameters: pGpLink - GpLink to free
  2550. //
  2551. //*************************************************************
  2552. void FreeGpLink( GPLINK *pGpLink )
  2553. {
  2554. if ( pGpLink ) {
  2555. LocalFree( pGpLink->pwszGPO );
  2556. LocalFree( pGpLink );
  2557. }
  2558. }
  2559. //*************************************************************
  2560. //
  2561. // AllocGpContainer()
  2562. //
  2563. // Purpose: Allocates a new struct for GpContainer
  2564. //
  2565. //
  2566. // Parameters: dwFlags - Flags
  2567. // bFound - Was Gpo found ?
  2568. // bAccessGranted - Was access granted ?
  2569. // bDisabled - Is Gp Container disabled ?
  2570. // dwVersion - Version #
  2571. // lpDSPath - DS path to Gpo
  2572. // lpFileSysPath - Sysvol path to Gpo
  2573. // lpDisplayName - Friendly name
  2574. // lpGpoName - Guid name
  2575. // pSD - Security descriptor
  2576. // cbSDLen - Length of security descriptor
  2577. // bFilterAllowed - Does GPO pass filter check
  2578. // pwszFilterId - WQL filter id
  2579. //
  2580. // Return: Pointer if successful
  2581. // NULL if an error occurs
  2582. //
  2583. //*************************************************************
  2584. GPCONTAINER *AllocGpContainer( DWORD dwFlags,
  2585. BOOL bFound,
  2586. BOOL bAccessGranted,
  2587. BOOL bDisabled,
  2588. DWORD dwVersion,
  2589. LPTSTR lpDSPath,
  2590. LPTSTR lpFileSysPath,
  2591. LPTSTR lpDisplayName,
  2592. LPTSTR lpGpoName,
  2593. PSECURITY_DESCRIPTOR pSD,
  2594. DWORD cbSDLen,
  2595. BOOL bFilterAllowed,
  2596. WCHAR *pwszFilterId,
  2597. LPWSTR szSOM,
  2598. DWORD dwOptions )
  2599. {
  2600. WCHAR wszMachPrefix[] = TEXT("LDAP://CN=Machine,");
  2601. INT iMachPrefixLen = lstrlen( wszMachPrefix );
  2602. WCHAR wszUserPrefix[] = TEXT("LDAP://CN=User,");
  2603. INT iUserPrefixLen = lstrlen( wszUserPrefix );
  2604. WCHAR *pwszPath = lpDSPath;
  2605. BOOL bResult = FALSE;
  2606. GPCONTAINER *pGpContainer = NULL;
  2607. XLastError xe;
  2608. HRESULT hr = S_OK;
  2609. //
  2610. // Strip out prefix, if any, to get the canonical path to Gpo
  2611. //
  2612. if ( (lstrlen(lpDSPath) > iUserPrefixLen)
  2613. && CompareString( LOCALE_INVARIANT, NORM_IGNORECASE,
  2614. lpDSPath, iUserPrefixLen, wszUserPrefix, iUserPrefixLen ) == CSTR_EQUAL ) {
  2615. pwszPath = lpDSPath + iUserPrefixLen;
  2616. } else if ( (lstrlen(lpDSPath) > iMachPrefixLen)
  2617. && CompareString( LOCALE_INVARIANT, NORM_IGNORECASE,
  2618. lpDSPath, iMachPrefixLen, wszMachPrefix, iMachPrefixLen ) == CSTR_EQUAL ) {
  2619. pwszPath = lpDSPath + iMachPrefixLen;
  2620. }
  2621. pGpContainer = (GPCONTAINER *) LocalAlloc( LPTR, sizeof(GPCONTAINER) );
  2622. if ( pGpContainer == NULL ) {
  2623. xe = GetLastError();
  2624. DebugMsg((DM_WARNING, TEXT("AllocGpContainer: Unable to allocate memory for GpContainer object")));
  2625. return NULL;
  2626. }
  2627. pGpContainer->bAccessDenied = !bAccessGranted;
  2628. pGpContainer->bFound = bFound;
  2629. if ( dwFlags & GP_MACHINE ) {
  2630. pGpContainer->bMachDisabled = bDisabled;
  2631. pGpContainer->dwMachVersion = dwVersion;
  2632. } else {
  2633. pGpContainer->bUserDisabled = bDisabled;
  2634. pGpContainer->dwUserVersion = dwVersion;
  2635. }
  2636. if ( pwszPath ) {
  2637. pGpContainer->pwszDSPath = (LPWSTR) LocalAlloc( LPTR, (lstrlen(pwszPath) + 1) * sizeof(WCHAR) );
  2638. if ( pGpContainer->pwszDSPath == NULL ) {
  2639. xe = GetLastError();
  2640. DebugMsg((DM_WARNING, TEXT("AllocGpContainer: Unable to allocate memory for GpContainer object")));
  2641. goto Exit;
  2642. }
  2643. hr = StringCchCopy( pGpContainer->pwszDSPath, lstrlen(pwszPath) + 1, pwszPath );
  2644. ASSERT(SUCCEEDED(hr));
  2645. }
  2646. if ( lpGpoName ) {
  2647. pGpContainer->pwszGPOName = (LPWSTR) LocalAlloc( LPTR, (lstrlen(lpGpoName) + 1) * sizeof(WCHAR) );
  2648. if ( pGpContainer->pwszGPOName == NULL ) {
  2649. xe = GetLastError();
  2650. DebugMsg((DM_WARNING, TEXT("AllocGpContainer: Unable to allocate memory for GpContainer object")));
  2651. goto Exit;
  2652. }
  2653. hr = StringCchCopy( pGpContainer->pwszGPOName, lstrlen(lpGpoName) + 1, lpGpoName );
  2654. ASSERT(SUCCEEDED(hr));
  2655. }
  2656. if ( lpDisplayName ) {
  2657. pGpContainer->pwszDisplayName = (LPWSTR) LocalAlloc( LPTR, (lstrlen(lpDisplayName) + 1) * sizeof(WCHAR) );
  2658. if ( pGpContainer->pwszDisplayName == NULL ) {
  2659. xe = GetLastError();
  2660. DebugMsg((DM_WARNING, TEXT("AllocGpContainer: Unable to allocate memory for GpContainer object")));
  2661. goto Exit;
  2662. }
  2663. hr = StringCchCopy( pGpContainer->pwszDisplayName, lstrlen(lpDisplayName) + 1, lpDisplayName );
  2664. ASSERT(SUCCEEDED(hr));
  2665. }
  2666. if ( lpFileSysPath ) {
  2667. pGpContainer->pwszFileSysPath = (LPWSTR) LocalAlloc( LPTR, (lstrlen(lpFileSysPath) + 1) * sizeof(WCHAR) );
  2668. if ( pGpContainer->pwszFileSysPath == NULL ) {
  2669. xe = GetLastError();
  2670. DebugMsg((DM_WARNING, TEXT("AllocGpContainer: Unable to allocate memory for GpContainer object")));
  2671. goto Exit;
  2672. }
  2673. hr = StringCchCopy( pGpContainer->pwszFileSysPath, lstrlen(lpFileSysPath) + 1, lpFileSysPath );
  2674. ASSERT(SUCCEEDED(hr));
  2675. }
  2676. if ( cbSDLen != 0 ) {
  2677. pGpContainer->pSD = (PSECURITY_DESCRIPTOR) LocalAlloc( LPTR, cbSDLen );
  2678. if ( pGpContainer->pSD == NULL ) {
  2679. xe = GetLastError();
  2680. DebugMsg((DM_WARNING, TEXT("AllocGpContainer: Unable to allocate memory for GpContainer object")));
  2681. goto Exit;
  2682. }
  2683. CopyMemory( pGpContainer->pSD, pSD, cbSDLen );
  2684. }
  2685. pGpContainer->cbSDLen = cbSDLen;
  2686. pGpContainer->bFilterAllowed = bFilterAllowed;
  2687. if ( pwszFilterId ) {
  2688. pGpContainer->pwszFilterId = (LPWSTR) LocalAlloc( LPTR, (lstrlen(pwszFilterId) + 1) * sizeof(WCHAR) );
  2689. if ( pGpContainer->pwszFilterId == NULL ) {
  2690. xe = GetLastError();
  2691. DebugMsg((DM_WARNING, TEXT("AllocGpContainer: Unable to allocate memory for GpContainer object")));
  2692. goto Exit;
  2693. }
  2694. hr = StringCchCopy( pGpContainer->pwszFilterId, lstrlen(pwszFilterId) + 1, pwszFilterId );
  2695. ASSERT(SUCCEEDED(hr));
  2696. }
  2697. if ( szSOM )
  2698. {
  2699. pGpContainer->szSOM = (LPWSTR) LocalAlloc( LPTR, (lstrlen(szSOM) + 1) * sizeof(WCHAR) );
  2700. if ( !pGpContainer->szSOM )
  2701. {
  2702. xe = GetLastError();
  2703. DebugMsg((DM_WARNING, TEXT("AllocGpContainer: Unable to allocate memory for GpContainer object")));
  2704. goto Exit;
  2705. }
  2706. hr = StringCchCopy( pGpContainer->szSOM, lstrlen(szSOM) + 1, szSOM );
  2707. ASSERT(SUCCEEDED(hr));
  2708. }
  2709. pGpContainer->dwOptions = dwOptions;
  2710. bResult = TRUE;
  2711. Exit:
  2712. if ( !bResult )
  2713. {
  2714. LocalFree( pGpContainer->pwszDSPath );
  2715. LocalFree( pGpContainer->pwszGPOName );
  2716. LocalFree( pGpContainer->pwszDisplayName );
  2717. LocalFree( pGpContainer->pwszFileSysPath );
  2718. LocalFree( pGpContainer->pSD );
  2719. LocalFree( pGpContainer->pwszFilterId );
  2720. LocalFree( pGpContainer->szSOM );
  2721. LocalFree( pGpContainer );
  2722. return 0;
  2723. }
  2724. return pGpContainer;
  2725. }
  2726. //*************************************************************
  2727. //
  2728. // FreeGpContainer()
  2729. //
  2730. // Purpose: Frees GpContainer struct
  2731. //
  2732. // Parameters: pGpContainer - Gp Container to free
  2733. //
  2734. //*************************************************************
  2735. void FreeGpContainer( GPCONTAINER *pGpContainer )
  2736. {
  2737. if ( pGpContainer ) {
  2738. LocalFree( pGpContainer->pwszDSPath );
  2739. LocalFree( pGpContainer->pwszGPOName );
  2740. LocalFree( pGpContainer->pwszDisplayName );
  2741. LocalFree( pGpContainer->pwszFileSysPath );
  2742. LocalFree( pGpContainer->pSD );
  2743. LocalFree( pGpContainer->pwszFilterId );
  2744. LocalFree( pGpContainer->szSOM );
  2745. LocalFree( pGpContainer );
  2746. }
  2747. }
  2748. //*************************************************************
  2749. //
  2750. // FreeSOMList()
  2751. //
  2752. // Purpose: Frees list of SOMs
  2753. //
  2754. // Parameters: pSOMList - SOM list to free
  2755. //
  2756. //*************************************************************
  2757. void FreeSOMList( SCOPEOFMGMT *pSOMList )
  2758. {
  2759. if ( pSOMList == NULL )
  2760. return;
  2761. while ( pSOMList ) {
  2762. SCOPEOFMGMT *pTemp = pSOMList->pNext;
  2763. FreeSOM( pSOMList );
  2764. pSOMList = pTemp;
  2765. }
  2766. }
  2767. //*************************************************************
  2768. //
  2769. // FreeGpContainerList()
  2770. //
  2771. // Purpose: Frees list of Gp Containers
  2772. //
  2773. // Parameters: pGpContainerList - Gp Container list to free
  2774. //
  2775. //*************************************************************
  2776. void FreeGpContainerList( GPCONTAINER *pGpContainerList )
  2777. {
  2778. if ( pGpContainerList == NULL )
  2779. return;
  2780. while ( pGpContainerList ) {
  2781. GPCONTAINER *pTemp = pGpContainerList->pNext;
  2782. FreeGpContainer( pGpContainerList );
  2783. pGpContainerList = pTemp;
  2784. }
  2785. }
  2786. LPTSTR GetSomPath( LPTSTR szContainer )
  2787. {
  2788. while (*szContainer) {
  2789. //
  2790. // See if the DN name starts with OU=
  2791. //
  2792. if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE,
  2793. szContainer, 3, TEXT("OU="), 3) == CSTR_EQUAL) {
  2794. break;
  2795. }
  2796. //
  2797. // See if the DN name starts with DC=
  2798. //
  2799. else if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE,
  2800. szContainer, 3, TEXT("DC="), 3) == CSTR_EQUAL) {
  2801. break;
  2802. }
  2803. //
  2804. // Move to the next chunk of the DN name
  2805. //
  2806. while (*szContainer && (*szContainer != TEXT(','))) {
  2807. szContainer++;
  2808. }
  2809. if (*szContainer == TEXT(',')) {
  2810. szContainer++;
  2811. }
  2812. }
  2813. if (!*szContainer) {
  2814. return NULL;
  2815. }
  2816. return szContainer;
  2817. }