Source code of Windows XP (NT5)
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.

1923 lines
58 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. polsvr.cpp
  5. Abstract:
  6. Server routines to get policy notification
  7. Author:
  8. Jin Huang (jinhuang) 17-Jun-1998
  9. Revision History:
  10. -*/
  11. #include "headers.h"
  12. #include "serverp.h"
  13. #include "pfp.h"
  14. #include "scesetup.h"
  15. #include "queue.h"
  16. #include <sddl.h>
  17. #include <ntldap.h>
  18. //#include <gpedit.h>
  19. //#include <initguid.h>
  20. //#include <gpeditp.h>
  21. #include <io.h>
  22. #pragma hdrstop
  23. DWORD
  24. ScepNotifyGetAuditPolicies(
  25. IN OUT PSCE_PROFILE_INFO pSmpInfo,
  26. IN PSCE_PROFILE_INFO pScpInfo OPTIONAL,
  27. IN BOOL bSaveToLocal,
  28. OUT BOOL *pbChanged
  29. );
  30. DWORD
  31. ScepNotifyPrivilegeChanges(
  32. IN SECURITY_DB_DELTA_TYPE DeltaType,
  33. IN PSID AccountSid,
  34. IN BOOL bAccountDeleted,
  35. IN OUT PSCE_PROFILE_INFO pSmpInfo,
  36. IN OUT PSCE_PROFILE_INFO pScpInfo OPTIONAL,
  37. IN BOOL bSaveToLocal,
  38. IN DWORD ExplicitLowRight,
  39. IN DWORD ExplicitHighRight,
  40. OUT BOOL *pbChanged
  41. );
  42. SCESTATUS
  43. ScepNotifySaveFixValueSection(
  44. IN PSCECONTEXT hProfile,
  45. IN PSCE_PROFILE_INFO pInfo,
  46. IN SCE_KEY_LOOKUP *Keys,
  47. IN DWORD cKeys,
  48. IN PCWSTR SectionName
  49. );
  50. SCESTATUS
  51. ScepNotifySavedAuditPolicy(
  52. IN PSCECONTEXT hProfile,
  53. IN PSCE_PROFILE_INFO pInfo
  54. );
  55. SCESTATUS
  56. ScepNotifySavedPrivileges(
  57. IN PSCECONTEXT hProfile,
  58. IN PSCE_PRIVILEGE_ASSIGNMENT pPrivList,
  59. IN PSCE_PRIVILEGE_ASSIGNMENT pMergedList
  60. );
  61. SCESTATUS
  62. ScepNotifySavedSystemAccess(
  63. IN PSCECONTEXT hProfile,
  64. IN PSCE_PROFILE_INFO pInfo
  65. );
  66. //*************************************************
  67. DWORD
  68. ScepNotifyGetChangedPolicies(
  69. IN SECURITY_DB_TYPE DbType,
  70. IN SECURITY_DB_DELTA_TYPE DeltaType,
  71. IN SECURITY_DB_OBJECT_TYPE ObjectType,
  72. IN PSID ObjectSid OPTIONAL,
  73. IN OUT PSCE_PROFILE_INFO pSmpInfo,
  74. IN PSCE_PROFILE_INFO pScpInfo OPTIONAL,
  75. IN BOOL bSaveToLocal,
  76. IN DWORD ExplicitLowRight,
  77. IN DWORD ExplicitHighRight,
  78. OUT BOOL *pbChanged
  79. )
  80. /*
  81. Routine Description:
  82. Determine if policy has been changed in this notification (DbType and ObjectType).
  83. If the effective policy buffer (pScpInfo) exists, should compare with
  84. effective policy buffer because that's the last policy configured
  85. on the system which may come from a domain GPO. If There is no effective
  86. policy (such as in seutp clean install), the local policy should be
  87. used to compare.
  88. Arguments:
  89. pSmpInfo - local policy
  90. pScpInfo - effective policy
  91. pbChanged - if the policy is changed, it's set to TRUE
  92. */
  93. {
  94. if ( pSmpInfo == NULL || pbChanged == NULL ) {
  95. return ERROR_INVALID_PARAMETER;
  96. }
  97. *pbChanged = FALSE;
  98. DWORD rc=ERROR_INVALID_PARAMETER;
  99. switch ( DbType) {
  100. case SecurityDbLsa:
  101. //
  102. // LSA policy changes
  103. //
  104. if ( ObjectType == SecurityDbObjectLsaPolicy ) {
  105. //
  106. // maybe audit policy is changed
  107. //
  108. rc = ScepNotifyGetAuditPolicies(pSmpInfo, pScpInfo, bSaveToLocal, pbChanged);
  109. } else {
  110. //
  111. // account policy is changed (user rights)
  112. //
  113. rc = ScepNotifyPrivilegeChanges(DeltaType,
  114. ObjectSid,
  115. FALSE,
  116. pSmpInfo,
  117. pScpInfo,
  118. bSaveToLocal,
  119. ExplicitLowRight,
  120. ExplicitHighRight,
  121. pbChanged);
  122. }
  123. break;
  124. case SecurityDbSam:
  125. //
  126. // SAM password and account policy changes
  127. //
  128. if ( ObjectType == SecurityDbObjectSamDomain ) {
  129. rc = ScepAnalyzeSystemAccess(pSmpInfo,
  130. pScpInfo,
  131. SCEPOL_SAVE_BUFFER |
  132. (bSaveToLocal ? SCEPOL_SAVE_DB : 0 ),
  133. pbChanged,
  134. NULL
  135. );
  136. ScepNotifyLogPolicy(rc, FALSE, L"Query/compare system access", DbType, ObjectType, NULL);
  137. } else {
  138. //
  139. // account is deleted. Should delete it from user rights
  140. //
  141. rc = ScepNotifyPrivilegeChanges(DeltaType,
  142. ObjectSid,
  143. TRUE,
  144. pSmpInfo,
  145. pScpInfo,
  146. bSaveToLocal,
  147. ExplicitLowRight,
  148. ExplicitHighRight,
  149. pbChanged);
  150. }
  151. break;
  152. default:
  153. rc = ERROR_INVALID_PARAMETER;
  154. }
  155. return rc;
  156. }
  157. DWORD
  158. ScepNotifyGetAuditPolicies(
  159. IN OUT PSCE_PROFILE_INFO pSmpInfo,
  160. IN PSCE_PROFILE_INFO pScpInfo OPTIONAL,
  161. IN BOOL bSaveToLocal,
  162. OUT BOOL *pbChanged
  163. )
  164. /*
  165. Routine Description:
  166. Determine if audit policy has been changed in this notification.
  167. If the effective policy buffer (pScpInfo) exists, should compare with
  168. effective policy buffer because that's the last policy configured
  169. on the system which may come from a domain GPO. If There is no effective
  170. policy (such as in seutp clean install), the local policy should be
  171. used to compare.
  172. Arguments:
  173. pSmpInfo - local policy
  174. pScpInfo - effective policy
  175. pbChanged - if the audit policy is changed, it's set to TRUE
  176. */
  177. {
  178. LSA_HANDLE lsaHandle=NULL;
  179. NTSTATUS status;
  180. DWORD rc;
  181. //
  182. // check if auditing policy is defined in the storage
  183. //
  184. PSCE_PROFILE_INFO pTmpInfo;
  185. if ( pScpInfo ) {
  186. pTmpInfo = pScpInfo;
  187. } else {
  188. pTmpInfo = pSmpInfo;
  189. }
  190. DWORD *pdwTemp = (DWORD *)&(pTmpInfo->AuditSystemEvents);
  191. BOOL bDefined=FALSE;
  192. for ( DWORD i=0; i<9; i++ ) {
  193. if ( *pdwTemp != SCE_NO_VALUE ) {
  194. bDefined = TRUE;
  195. break;
  196. }
  197. pdwTemp++;
  198. }
  199. if ( !bDefined ) {
  200. ScepNotifyLogPolicy(0, FALSE, L"No audit policy is defined", SecurityDbLsa, SecurityDbObjectLsaPolicy, NULL );
  201. return ERROR_SUCCESS;
  202. }
  203. //
  204. // open Lsa policy for read/write
  205. //
  206. ScepNotifyLogPolicy(0, FALSE, L"Open LSA", SecurityDbLsa, SecurityDbObjectLsaPolicy, NULL );
  207. status = ScepOpenLsaPolicy(
  208. POLICY_VIEW_AUDIT_INFORMATION |
  209. POLICY_AUDIT_LOG_ADMIN,
  210. &lsaHandle,
  211. TRUE
  212. );
  213. if ( !NT_SUCCESS(status) ) {
  214. lsaHandle = NULL;
  215. rc = RtlNtStatusToDosError( status );
  216. ScepNotifyLogPolicy(rc, FALSE, L"Open failed", SecurityDbLsa, SecurityDbObjectLsaPolicy, NULL );
  217. return(rc);
  218. }
  219. PPOLICY_AUDIT_EVENTS_INFO pAuditEvent=NULL;
  220. //
  221. // Query audit event information
  222. //
  223. status = LsaQueryInformationPolicy( lsaHandle,
  224. PolicyAuditEventsInformation,
  225. (PVOID *)&pAuditEvent
  226. );
  227. rc = RtlNtStatusToDosError( status );
  228. ScepNotifyLogPolicy(rc, FALSE, L"Query Audit", SecurityDbLsa, SecurityDbObjectLsaPolicy, NULL );
  229. if ( NT_SUCCESS( status ) ) {
  230. //
  231. // restore the auditing mode
  232. //
  233. DWORD *pdwAuditAddr=&(pTmpInfo->AuditSystemEvents);
  234. DWORD *pdwLocalAudit=&(pSmpInfo->AuditSystemEvents);
  235. DWORD dwVal;
  236. for ( ULONG i=0; i<pAuditEvent->MaximumAuditEventCount && i<9; i++ ) {
  237. //
  238. // because secedit buffer is not defined in the exact same sequence as
  239. // POLICY_AUDIT_EVENT_TYPE, have to case this
  240. //
  241. dwVal = pAuditEvent->AuditingMode ? pAuditEvent->EventAuditingOptions[i] : 0;
  242. switch ( i ) {
  243. case AuditCategoryDetailedTracking:
  244. if ( pTmpInfo->AuditProcessTracking != SCE_NO_VALUE &&
  245. pTmpInfo->AuditProcessTracking != dwVal ) {
  246. // save the setting in local policy table
  247. pSmpInfo->AuditProcessTracking = dwVal;
  248. *pbChanged = TRUE;
  249. } else if ( bSaveToLocal ) {
  250. //
  251. // turn this item off to indicate this one is not changed
  252. //
  253. pSmpInfo->AuditProcessTracking = SCE_NO_VALUE;
  254. }
  255. break;
  256. case AuditCategoryPolicyChange:
  257. if ( pTmpInfo->AuditPolicyChange != SCE_NO_VALUE &&
  258. pTmpInfo->AuditPolicyChange != dwVal ) {
  259. pSmpInfo->AuditPolicyChange = dwVal;
  260. *pbChanged = TRUE;
  261. } else if ( bSaveToLocal ) {
  262. //
  263. // turn this item off to indicate this one is not changed
  264. //
  265. pSmpInfo->AuditPolicyChange = SCE_NO_VALUE;
  266. }
  267. break;
  268. case AuditCategoryAccountManagement:
  269. if ( pTmpInfo->AuditAccountManage != SCE_NO_VALUE &&
  270. pTmpInfo->AuditAccountManage != dwVal ) {
  271. pSmpInfo->AuditAccountManage = dwVal;
  272. *pbChanged = TRUE;
  273. } else if ( bSaveToLocal ) {
  274. //
  275. // turn this item off to indicate this one is not changed
  276. //
  277. pSmpInfo->AuditAccountManage = SCE_NO_VALUE;
  278. }
  279. break;
  280. default:
  281. if ( pdwAuditAddr[i] != SCE_NO_VALUE &&
  282. pdwAuditAddr[i] != dwVal ) {
  283. pdwLocalAudit[i] = dwVal;
  284. *pbChanged = TRUE;
  285. } else if ( bSaveToLocal ) {
  286. //
  287. // turn this item off to indicate this one is not changed
  288. //
  289. pdwLocalAudit[i] = SCE_NO_VALUE;
  290. }
  291. break;
  292. }
  293. }
  294. LsaFreeMemory((PVOID)pAuditEvent);
  295. }
  296. LsaClose( lsaHandle );
  297. return(rc);
  298. }
  299. DWORD
  300. ScepNotifyPrivilegeChanges(
  301. IN SECURITY_DB_DELTA_TYPE DeltaType,
  302. IN PSID AccountSid,
  303. IN BOOL bAccountDeleted,
  304. IN OUT PSCE_PROFILE_INFO pSmpInfo,
  305. IN OUT PSCE_PROFILE_INFO pScpInfo OPTIONAL,
  306. IN BOOL bSaveToLocal,
  307. IN DWORD ExplicitLowRight,
  308. IN DWORD ExplicitHighRight,
  309. IN BOOL *pbChanged
  310. )
  311. /*
  312. Routine Description:
  313. Determine if user rights has been changed in this notification.
  314. If the effective policy buffer (pScpInfo) exists, should compare with
  315. effective policy buffer because that's the last policy configured
  316. on the system which may come from a domain GPO. If There is no effective
  317. policy (such as in seutp clean install), the local policy should be
  318. used to compare.
  319. User rights should all come in the exact same format as defined in policy
  320. storage (for example, SID string or free text names). There is no account
  321. lookup in the query.
  322. Arguments:
  323. pSmpInfo - local policy
  324. pScpInfo - effective policy
  325. pbChanged - if the user rights is changed, it's set to TRUE
  326. */
  327. {
  328. if ( AccountSid == NULL || pSmpInfo == NULL ) {
  329. return ERROR_INVALID_PARAMETER;
  330. }
  331. //
  332. // open Lsa policy
  333. //
  334. LSA_HANDLE lsaHandle=NULL;
  335. NTSTATUS NtStatus;
  336. DWORD rc=0;
  337. //
  338. // open Lsa policy for read/write
  339. //
  340. ScepNotifyLogPolicy(0, FALSE, L"Open LSA", SecurityDbLsa, SecurityDbObjectLsaAccount, NULL );
  341. // GENERIC_READ | GENERIC_EXECUTE | bug in LsaOpenPolicy, can't pass in generic access
  342. NtStatus = ScepOpenLsaPolicy(
  343. POLICY_VIEW_LOCAL_INFORMATION |
  344. POLICY_LOOKUP_NAMES,
  345. &lsaHandle,
  346. TRUE
  347. );
  348. if ( !NT_SUCCESS(NtStatus) ) {
  349. lsaHandle = NULL;
  350. ScepNotifyLogPolicy(RtlNtStatusToDosError(NtStatus),
  351. FALSE,
  352. L"Open Failed",
  353. SecurityDbLsa,
  354. SecurityDbObjectLsaAccount,
  355. NULL );
  356. return ( RtlNtStatusToDosError( NtStatus ) );
  357. }
  358. ScepNotifyLogPolicy(0,
  359. FALSE,
  360. L"Open completed",
  361. SecurityDbLsa,
  362. SecurityDbObjectLsaAccount,
  363. NULL );
  364. PWSTR StringSid=NULL;
  365. DWORD StringLen=0;
  366. //
  367. // convert sid to sid string
  368. //
  369. ScepConvertSidToPrefixStringSid(AccountSid, &StringSid);
  370. ScepNotifyLogPolicy(0, FALSE, L"Convert to string SID", SecurityDbLsa, SecurityDbObjectLsaAccount, StringSid );
  371. LPTSTR AccountName = NULL;
  372. DWORD Len=0;
  373. if ( !bAccountDeleted ) {
  374. //
  375. // translate account sid to name
  376. //
  377. BOOL bFromAccountDomain = ScepIsSidFromAccountDomain( AccountSid );
  378. NtStatus = ScepConvertSidToName(
  379. lsaHandle,
  380. AccountSid,
  381. bFromAccountDomain,
  382. &AccountName,
  383. &Len
  384. );
  385. rc = RtlNtStatusToDosError(NtStatus);
  386. ScepNotifyLogPolicy(rc,
  387. FALSE,
  388. L"Get Account Name",
  389. SecurityDbLsa,
  390. SecurityDbObjectLsaAccount,
  391. AccountName ? AccountName : StringSid);
  392. }
  393. DWORD dwPrivLowHeld, dwPrivHighHeld;
  394. if ( AccountName || StringSid ) {
  395. NtStatus = STATUS_SUCCESS;
  396. //
  397. // find out the account name pointer (without domain prefix)
  398. //
  399. PWSTR pNameStart = NULL;
  400. if ( AccountName ) {
  401. pNameStart = wcschr(AccountName, L'\\');
  402. if ( pNameStart ) {
  403. //
  404. // domain relative account, check if this is from a foreign domain
  405. //
  406. UNICODE_STRING u;
  407. u.Buffer = AccountName;
  408. u.Length = ((USHORT)(pNameStart-AccountName))*sizeof(WCHAR);
  409. if ( ScepIsDomainLocal(&u) ) {
  410. //
  411. // local domain (builtin, account, ...)
  412. // this can be used to match free text accounts
  413. //
  414. pNameStart++;
  415. } else {
  416. //
  417. // account from a foreign domain
  418. // do not allow mapping of free text accounts
  419. //
  420. pNameStart = NULL;
  421. }
  422. } else pNameStart = AccountName;
  423. }
  424. if ( StringSid ) StringLen = wcslen(StringSid);
  425. if ( DeltaType == SecurityDbDelete ) {
  426. dwPrivLowHeld = 0;
  427. dwPrivHighHeld = 0;
  428. } else if ( ExplicitLowRight != 0 ||
  429. ExplicitHighRight != 0 ) {
  430. dwPrivLowHeld = ExplicitLowRight;
  431. dwPrivHighHeld = ExplicitHighRight;
  432. } else {
  433. //
  434. // get all privileges assigned to this account
  435. //
  436. NtStatus = ScepGetAccountExplicitRight(
  437. lsaHandle,
  438. AccountSid,
  439. &dwPrivLowHeld,
  440. &dwPrivHighHeld
  441. );
  442. }
  443. rc = RtlNtStatusToDosError(NtStatus);
  444. WCHAR Msg[50];
  445. swprintf(Msg, L"Get Priv/Right %8x %8x\0", dwPrivHighHeld, dwPrivLowHeld);
  446. ScepNotifyLogPolicy(rc,
  447. FALSE,
  448. Msg,
  449. SecurityDbLsa,
  450. SecurityDbObjectLsaAccount,
  451. AccountName ? AccountName : StringSid );
  452. if ( NT_SUCCESS(NtStatus) ) {
  453. //
  454. // loop through each privilege defined in SCE to add/remove the account
  455. //
  456. PSCE_PRIVILEGE_ASSIGNMENT pTemp, pTemp2;
  457. PSCE_NAME_LIST pName, pParent, pName2, pParent2;
  458. INT i;
  459. for ( pTemp2=pSmpInfo->OtherInfo.smp.pPrivilegeAssignedTo;
  460. pTemp2 != NULL; pTemp2=pTemp2->Next ) {
  461. pTemp2->Status = SCE_STATUS_NOT_CONFIGURED;
  462. }
  463. if ( pScpInfo && bSaveToLocal ) {
  464. //
  465. // !!!do this only when save to database!!!
  466. // if there is effective policy, compare with effective rights
  467. // modify both effective policy list and local policy list
  468. //
  469. for ( pTemp=pScpInfo->OtherInfo.smp.pPrivilegeAssignedTo;
  470. pTemp != NULL; pTemp=pTemp->Next ) {
  471. pTemp->Status = 0;
  472. i = ScepLookupPrivByName(pTemp->Name);
  473. if ( i > -1 ) {
  474. //
  475. // find the local policy match
  476. //
  477. for ( pTemp2=pSmpInfo->OtherInfo.smp.pPrivilegeAssignedTo;
  478. pTemp2 != NULL; pTemp2=pTemp2->Next ) {
  479. if ( _wcsicmp(pTemp->Name, pTemp2->Name) == 0 ) {
  480. // find it
  481. break;
  482. }
  483. }
  484. //
  485. // compare with effective policy
  486. // try to find in string sid first, then full account name,
  487. // and last free text account
  488. //
  489. for ( pName=pTemp->AssignedTo, pParent=NULL;
  490. pName != NULL; pParent=pName, pName = pName->Next ) {
  491. if ( (StringSid && _wcsicmp(StringSid, pName->Name) == 0) ||
  492. (AccountName && _wcsicmp(AccountName, pName->Name) == 0) ||
  493. (pNameStart && _wcsicmp(pNameStart, pName->Name) == 0) ) {
  494. // find it
  495. break;
  496. }
  497. }
  498. //
  499. // also find the match in local policy (if there is any)
  500. // try to find in string sid first, then full account name,
  501. // and last free text account
  502. //
  503. if ( pTemp2 ) {
  504. pTemp2->Status = 0;
  505. for ( pName2=pTemp2->AssignedTo, pParent2=NULL;
  506. pName2 != NULL; pParent2=pName2, pName2 = pName2->Next ) {
  507. if ( (StringSid && _wcsicmp(StringSid, pName2->Name) == 0) ||
  508. (AccountName && _wcsicmp(AccountName, pName2->Name) == 0) ||
  509. (pNameStart && _wcsicmp(pNameStart, pName2->Name) == 0) ) {
  510. // find it
  511. break;
  512. }
  513. }
  514. } else {
  515. pName2 = NULL;
  516. pParent2 = NULL;
  517. }
  518. //
  519. // now adjust the lists
  520. //
  521. if ( ( ( i < 32 ) && ( dwPrivLowHeld & (1 << i) ) ) ||
  522. ( ( i >= 32 ) && ( dwPrivHighHeld & (1 << (i-32) ) ) ) ) {
  523. if ( pName == NULL ) {
  524. //
  525. // add this node to effective list
  526. //
  527. rc = ScepAddToNameList(&(pTemp->AssignedTo),
  528. StringSid ? StringSid : AccountName,
  529. StringSid ? StringLen : Len);
  530. *pbChanged = TRUE;
  531. pTemp->Status = SCE_STATUS_MISMATCH;
  532. if ( rc != ERROR_SUCCESS ) {
  533. break;
  534. }
  535. }
  536. if ( (pTemp2 != NULL) && (pName2 == NULL) ) {
  537. //
  538. // should add this node to local policy node
  539. //
  540. rc = ScepAddToNameList(&(pTemp2->AssignedTo),
  541. StringSid ? StringSid : AccountName,
  542. StringSid ? StringLen : Len);
  543. *pbChanged = TRUE;
  544. pTemp2->Status = SCE_STATUS_MISMATCH;
  545. if ( rc != ERROR_SUCCESS ) {
  546. break;
  547. }
  548. }
  549. } else {
  550. if ( pName ) {
  551. //
  552. // should remove it from effective list
  553. //
  554. if ( pParent ) {
  555. pParent->Next = pName->Next;
  556. } else {
  557. pTemp->AssignedTo = pName->Next;
  558. }
  559. pName->Next = NULL;
  560. ScepFree(pName->Name);
  561. ScepFree(pName);
  562. pName = NULL;
  563. *pbChanged = TRUE;
  564. pTemp->Status = SCE_STATUS_MISMATCH;
  565. }
  566. if ( pTemp2 && pName2 ) {
  567. //
  568. // should remove it from local list
  569. //
  570. if ( pParent2 ) {
  571. pParent2->Next = pName2->Next;
  572. } else {
  573. pTemp2->AssignedTo = pName2->Next;
  574. }
  575. pName2->Next = NULL;
  576. ScepFree(pName2->Name);
  577. ScepFree(pName2);
  578. pName2 = NULL;
  579. *pbChanged = TRUE;
  580. pTemp2->Status = SCE_STATUS_MISMATCH;
  581. }
  582. }
  583. if ( i < 32 ) {
  584. dwPrivLowHeld &= ~(1 << i);
  585. } else {
  586. dwPrivHighHeld &= ~(1 << (i-32) );
  587. }
  588. }
  589. }
  590. }
  591. for ( pTemp=pSmpInfo->OtherInfo.smp.pPrivilegeAssignedTo;
  592. pTemp != NULL; pTemp=pTemp->Next ) {
  593. if ( pTemp->Status != SCE_STATUS_NOT_CONFIGURED ) {
  594. //
  595. // this one was already checked in previous loop
  596. //
  597. continue;
  598. }
  599. //
  600. // when get here, this privilege must not be found
  601. // in the effective right list (or the effective
  602. // right list is NULL)
  603. //
  604. pTemp->Status = 0;
  605. i = ScepLookupPrivByName(pTemp->Name);
  606. if ( i > -1 ) {
  607. //
  608. // detect if anything changed (with the local policy)
  609. //
  610. for ( pName=pTemp->AssignedTo, pParent=NULL;
  611. pName != NULL; pParent=pName, pName = pName->Next ) {
  612. if ( (StringSid && _wcsicmp(StringSid, pName->Name) == 0) ||
  613. (AccountName && _wcsicmp(AccountName, pName->Name) == 0) ||
  614. (pNameStart && _wcsicmp(pNameStart, pName->Name) == 0) ) {
  615. // find it
  616. break;
  617. }
  618. }
  619. if ( ( ( i < 32 ) && ( dwPrivLowHeld & (1 << i) ) ) ||
  620. ( ( i >= 32 ) && ( dwPrivHighHeld & (1 << (i-32) ) ) ) ) {
  621. if ( pName == NULL ) {
  622. //
  623. // should add this node
  624. //
  625. rc = ScepAddToNameList(&(pTemp->AssignedTo),
  626. StringSid ? StringSid : AccountName,
  627. StringSid ? StringLen : Len);
  628. *pbChanged = TRUE;
  629. pTemp->Status = SCE_STATUS_MISMATCH;
  630. if ( rc != ERROR_SUCCESS ) {
  631. break;
  632. }
  633. }
  634. } else {
  635. if ( pName ) {
  636. //
  637. // should remove it
  638. //
  639. if ( pParent ) {
  640. pParent->Next = pName->Next;
  641. } else {
  642. pTemp->AssignedTo = pName->Next;
  643. }
  644. pName->Next = NULL;
  645. ScepFree(pName->Name);
  646. ScepFree(pName);
  647. pName = NULL;
  648. *pbChanged = TRUE;
  649. pTemp->Status = SCE_STATUS_MISMATCH;
  650. }
  651. }
  652. if ( i < 32 ) {
  653. dwPrivLowHeld &= ~(1 << i);
  654. } else {
  655. dwPrivHighHeld &= ~(1 << (i-32) );
  656. }
  657. }
  658. }
  659. #if 0
  660. //
  661. // if the privilege is not covered by the template/db,
  662. // do not trap it becuase user explicitly exclude this one.
  663. //
  664. if ( rc == ERROR_SUCCESS &&
  665. ( dwPrivLowHeld || dwPrivHighHeld ) ) {
  666. //
  667. // other new privileges added which are not in the template
  668. //
  669. for ( i=0; i<cPrivCnt; i++) {
  670. if ( ( ( i < 32 ) && ( dwPrivLowHeld & (1 << i) ) ) ||
  671. ( ( i >= 32 ) && ( dwPrivHighHeld & (1 << (i-32) ) ) ) ) {
  672. //
  673. // add this account/right to the list
  674. //
  675. rc = ERROR_NOT_ENOUGH_MEMORY;
  676. pTemp = (PSCE_PRIVILEGE_ASSIGNMENT)ScepAlloc( LMEM_ZEROINIT,
  677. sizeof(SCE_PRIVILEGE_ASSIGNMENT) );
  678. if ( pTemp ) {
  679. pTemp->Name = (PWSTR)ScepAlloc( (UINT)0, (wcslen(SCE_Privileges[i].Name)+1)*sizeof(WCHAR));
  680. if ( pTemp->Name != NULL ) {
  681. wcscpy(pTemp->Name, SCE_Privileges[i].Name);
  682. pTemp->Status = SCE_STATUS_GOOD;
  683. pTemp->AssignedTo = NULL;
  684. rc = ScepAddToNameList(&(pTemp->AssignedTo),
  685. StringSid ? StringSid : AccountName,
  686. StringSid ? StringLen : Len);
  687. *pbChanged = TRUE;
  688. if ( rc != ERROR_SUCCESS ) {
  689. ScepFree(pTemp->Name);
  690. }
  691. }
  692. if ( ERROR_SUCCESS != rc ) {
  693. ScepFree(pTemp);
  694. }
  695. }
  696. if ( ERROR_SUCCESS == rc ) {
  697. //
  698. // add this node to the list
  699. //
  700. pTemp->Next = pSceInfo->OtherInfo.smp.pPrivilegeAssignedTo;
  701. pSceInfo->OtherInfo.smp.pPrivilegeAssignedTo = pTemp;
  702. pTemp = NULL;
  703. } else {
  704. break;
  705. }
  706. }
  707. } // loop to the next privilege
  708. } // there are new privileges added to the template
  709. #endif
  710. ScepNotifyLogPolicy(rc,
  711. FALSE,
  712. L"Rights Modified",
  713. SecurityDbLsa,
  714. SecurityDbObjectLsaAccount,
  715. AccountName ? AccountName : StringSid);
  716. } // success getting current privileges assigned to the account
  717. }
  718. if ( AccountName ) {
  719. LocalFree(AccountName);
  720. }
  721. if ( StringSid ) {
  722. LocalFree(StringSid);
  723. }
  724. LsaClose( lsaHandle );
  725. return rc;
  726. }
  727. DWORD
  728. ScepNotifySaveChangedPolicies(
  729. IN PSCECONTEXT hProfile,
  730. IN SECURITY_DB_TYPE DbType,
  731. IN AREA_INFORMATION Area,
  732. IN PSCE_PROFILE_INFO pInfo,
  733. IN PSCE_PROFILE_INFO pMergedInfo OPTIONAL
  734. )
  735. {
  736. if ( hProfile == NULL || pInfo == NULL ) {
  737. return(SCESTATUS_INVALID_PARAMETER);
  738. }
  739. SCESTATUS rc;
  740. rc = SceJetStartTransaction( hProfile );
  741. if ( rc == SCESTATUS_SUCCESS ) {
  742. if ( Area & AREA_SECURITY_POLICY ) {
  743. //
  744. // handle auditing policy
  745. //
  746. if ( DbType == SecurityDbLsa ) {
  747. rc = ScepNotifySavedAuditPolicy(hProfile,
  748. pInfo
  749. );
  750. } else {
  751. rc = ScepNotifySavedSystemAccess(hProfile,
  752. pInfo
  753. );
  754. }
  755. }
  756. if ( (SCESTATUS_SUCCESS == rc) &&
  757. (Area & AREA_PRIVILEGES) ) {
  758. //
  759. // handle user rights.
  760. //
  761. rc = ScepNotifySavedPrivileges(hProfile,
  762. pInfo->OtherInfo.smp.pPrivilegeAssignedTo,
  763. pMergedInfo ? pMergedInfo->OtherInfo.smp.pPrivilegeAssignedTo : NULL
  764. );
  765. }
  766. if ( rc == SCESTATUS_SUCCESS ) {
  767. //
  768. // needs return code for commiting the transaction
  769. //
  770. rc = SceJetCommitTransaction(hProfile, 0);
  771. }
  772. if ( rc != SCESTATUS_SUCCESS ) {
  773. SceJetRollback(hProfile, 0);
  774. }
  775. }
  776. return( ScepSceStatusToDosError(rc) );
  777. }
  778. SCESTATUS
  779. ScepNotifySavedAuditPolicy(
  780. IN PSCECONTEXT hProfile,
  781. IN PSCE_PROFILE_INFO pInfo
  782. )
  783. {
  784. SCE_KEY_LOOKUP EventKeys[]={
  785. {(PWSTR)TEXT("AuditSystemEvents"), offsetof(struct _SCE_PROFILE_INFO, AuditSystemEvents), 'D'},
  786. {(PWSTR)TEXT("AuditLogonEvents"), offsetof(struct _SCE_PROFILE_INFO, AuditLogonEvents), 'D'},
  787. {(PWSTR)TEXT("AuditObjectAccess"), offsetof(struct _SCE_PROFILE_INFO, AuditObjectAccess), 'D'},
  788. {(PWSTR)TEXT("AuditPrivilegeUse"), offsetof(struct _SCE_PROFILE_INFO, AuditPrivilegeUse), 'D'},
  789. {(PWSTR)TEXT("AuditPolicyChange"), offsetof(struct _SCE_PROFILE_INFO, AuditPolicyChange), 'D'},
  790. {(PWSTR)TEXT("AuditAccountManage"), offsetof(struct _SCE_PROFILE_INFO, AuditAccountManage), 'D'},
  791. {(PWSTR)TEXT("AuditProcessTracking"),offsetof(struct _SCE_PROFILE_INFO, AuditProcessTracking),'D'},
  792. {(PWSTR)TEXT("AuditDSAccess"), offsetof(struct _SCE_PROFILE_INFO, AuditDSAccess), 'D'},
  793. {(PWSTR)TEXT("AuditAccountLogon"), offsetof(struct _SCE_PROFILE_INFO, AuditAccountLogon), 'D'}};
  794. DWORD cKeys = sizeof(EventKeys) / sizeof(SCE_KEY_LOOKUP);
  795. if ( hProfile == NULL || pInfo == NULL ) {
  796. return(SCESTATUS_INVALID_PARAMETER);
  797. }
  798. return( ScepNotifySaveFixValueSection(
  799. hProfile,
  800. pInfo,
  801. EventKeys,
  802. cKeys,
  803. szAuditEvent
  804. ) );
  805. }
  806. SCESTATUS
  807. ScepNotifySavedSystemAccess(
  808. IN PSCECONTEXT hProfile,
  809. IN PSCE_PROFILE_INFO pInfo
  810. )
  811. {
  812. SCE_KEY_LOOKUP AccessKeys[] = {
  813. {(PWSTR)TEXT("MinimumPasswordAge"), offsetof(struct _SCE_PROFILE_INFO, MinimumPasswordAge), 'D'},
  814. {(PWSTR)TEXT("MaximumPasswordAge"), offsetof(struct _SCE_PROFILE_INFO, MaximumPasswordAge), 'D'},
  815. {(PWSTR)TEXT("MinimumPasswordLength"), offsetof(struct _SCE_PROFILE_INFO, MinimumPasswordLength), 'D'},
  816. {(PWSTR)TEXT("PasswordComplexity"), offsetof(struct _SCE_PROFILE_INFO, PasswordComplexity), 'D'},
  817. {(PWSTR)TEXT("PasswordHistorySize"), offsetof(struct _SCE_PROFILE_INFO, PasswordHistorySize), 'D'},
  818. {(PWSTR)TEXT("LockoutBadCount"), offsetof(struct _SCE_PROFILE_INFO, LockoutBadCount), 'D'},
  819. {(PWSTR)TEXT("ResetLockoutCount"), offsetof(struct _SCE_PROFILE_INFO, ResetLockoutCount), 'D'},
  820. {(PWSTR)TEXT("LockoutDuration"), offsetof(struct _SCE_PROFILE_INFO, LockoutDuration), 'D'},
  821. {(PWSTR)TEXT("RequireLogonToChangePassword"),offsetof(struct _SCE_PROFILE_INFO, RequireLogonToChangePassword),'D'},
  822. {(PWSTR)TEXT("ForceLogoffWhenHourExpire"),offsetof(struct _SCE_PROFILE_INFO, ForceLogoffWhenHourExpire),'D'},
  823. {(PWSTR)TEXT("ClearTextPassword"), offsetof(struct _SCE_PROFILE_INFO, ClearTextPassword), 'D'}
  824. };
  825. DWORD cKeys = sizeof(AccessKeys) / sizeof(SCE_KEY_LOOKUP);
  826. if ( hProfile == NULL || pInfo == NULL ) {
  827. return(SCESTATUS_INVALID_PARAMETER);
  828. }
  829. return( ScepNotifySaveFixValueSection(
  830. hProfile,
  831. pInfo,
  832. AccessKeys,
  833. cKeys,
  834. szSystemAccess
  835. ) );
  836. }
  837. SCESTATUS
  838. ScepNotifySaveFixValueSection(
  839. IN PSCECONTEXT hProfile,
  840. IN PSCE_PROFILE_INFO pInfo,
  841. IN SCE_KEY_LOOKUP *Keys,
  842. IN DWORD cKeys,
  843. IN PCWSTR SectionName
  844. )
  845. {
  846. SCESTATUS rc;
  847. PSCESECTION hSectionSmp=NULL, hSectionScp=NULL;
  848. DWORD i;
  849. UINT Offset;
  850. DWORD valNewScep;
  851. //
  852. // open smp section for system access
  853. //
  854. rc = ScepOpenSectionForName(
  855. hProfile,
  856. SCE_ENGINE_SMP,
  857. SectionName,
  858. &hSectionSmp
  859. );
  860. if ( rc == SCESTATUS_SUCCESS ) {
  861. DWORD dwThisTable = hProfile->Type & 0xF0L;
  862. if ( SCEJET_MERGE_TABLE_1 == dwThisTable ||
  863. SCEJET_MERGE_TABLE_2 == dwThisTable ) {
  864. if ( SCESTATUS_SUCCESS != ScepOpenSectionForName(
  865. hProfile,
  866. SCE_ENGINE_SCP,
  867. SectionName,
  868. &hSectionScp
  869. ) ) {
  870. hSectionScp = NULL;
  871. }
  872. }
  873. for ( i=0; i<cKeys; i++) {
  874. //
  875. // get settings in AccessLookup table
  876. //
  877. Offset = Keys[i].Offset;
  878. switch ( Keys[i].BufferType ) {
  879. case 'B':
  880. break;
  881. case 'D':
  882. valNewScep = *((DWORD *)((CHAR *)pInfo+Offset));
  883. //
  884. // update the SMP entry
  885. //
  886. rc = ScepCompareAndSaveIntValue(
  887. hSectionSmp,
  888. Keys[i].KeyString,
  889. FALSE,
  890. SCE_NO_VALUE,
  891. valNewScep
  892. );
  893. if ( rc == SCESTATUS_RECORD_NOT_FOUND ) {
  894. //
  895. // if not find for delete, ignore the error
  896. //
  897. rc = SCESTATUS_SUCCESS;
  898. } else if ( SCESTATUS_SUCCESS == rc &&
  899. hSectionScp ) {
  900. //
  901. // update the SCP entry, ignore error
  902. //
  903. ScepCompareAndSaveIntValue(
  904. hSectionScp,
  905. Keys[i].KeyString,
  906. FALSE,
  907. SCE_NO_VALUE,
  908. valNewScep
  909. );
  910. }
  911. break;
  912. default:
  913. break;
  914. }
  915. if ( rc != SCESTATUS_SUCCESS ) {
  916. break;
  917. }
  918. }
  919. if ( hSectionScp ) {
  920. SceJetCloseSection(&hSectionScp, TRUE);
  921. }
  922. SceJetCloseSection(&hSectionSmp, TRUE);
  923. }
  924. return(rc);
  925. }
  926. SCESTATUS
  927. ScepNotifySavedPrivileges(
  928. IN PSCECONTEXT hProfile,
  929. IN PSCE_PRIVILEGE_ASSIGNMENT pPrivList,
  930. IN PSCE_PRIVILEGE_ASSIGNMENT pMergedList OPTIONAL
  931. )
  932. /*
  933. Routine Description:
  934. Update privileges from
  935. Arguements:
  936. hProfile - the jet database handle
  937. pPrivList - the changed privilege buffer
  938. Return Value:
  939. SCESTATUS
  940. */
  941. {
  942. SCESTATUS rc;
  943. PSCESECTION hSectionSmp=NULL, hSectionScp=NULL;
  944. PSCE_PRIVILEGE_ASSIGNMENT pPriv;
  945. if ( hProfile == NULL ) {
  946. return(SCESTATUS_INVALID_PARAMETER);
  947. }
  948. if ( pPrivList == NULL ) {
  949. return(SCESTATUS_SUCCESS);
  950. }
  951. LSA_HANDLE lsaHandle=NULL;
  952. /* no need to lookup account in save
  953. rc = RtlNtStatusToDosError(
  954. ScepOpenLsaPolicy(
  955. MAXIMUM_ALLOWED,
  956. &lsaHandle,
  957. TRUE
  958. ));
  959. if ( ERROR_SUCCESS != rc ) {
  960. lsaHandle = NULL;
  961. ScepNotifyLogPolicy(rc, FALSE, L"Open failed", SecurityDbLsa, SecurityDbObjectLsaPolicy, NULL );
  962. return(ScepDosErrorToSceStatus(rc));
  963. }
  964. */
  965. //
  966. // open smp section for privileges
  967. //
  968. rc = ScepOpenSectionForName(
  969. hProfile,
  970. SCE_ENGINE_SMP,
  971. szPrivilegeRights,
  972. &hSectionSmp
  973. );
  974. if ( rc == SCESTATUS_SUCCESS ) {
  975. // if SCP is different then SMP, open it
  976. DWORD dwThisTable = hProfile->Type & 0xF0L;
  977. if ( SCEJET_MERGE_TABLE_1 == dwThisTable ||
  978. SCEJET_MERGE_TABLE_2 == dwThisTable ) {
  979. if ( SCESTATUS_SUCCESS != ScepOpenSectionForName(
  980. hProfile,
  981. SCE_ENGINE_SCP,
  982. szPrivilegeRights,
  983. &hSectionScp
  984. ) ) {
  985. hSectionScp = NULL;
  986. }
  987. }
  988. for ( pPriv=pPrivList; pPriv != NULL; pPriv = pPriv->Next ) {
  989. //
  990. // Process each privilege in the new list
  991. // Update SMP with new value
  992. //
  993. if ( pPriv->Status == SCE_STATUS_MISMATCH ) {
  994. //
  995. // this is in name format, should convert it
  996. //
  997. rc = ScepWriteNameListValue(
  998. lsaHandle,
  999. hSectionSmp,
  1000. pPriv->Name,
  1001. pPriv->AssignedTo,
  1002. SCE_WRITE_EMPTY_LIST, // | SCE_WRITE_CONVERT, no need to lookup
  1003. 0
  1004. );
  1005. if ( rc == SCESTATUS_RECORD_NOT_FOUND ) {
  1006. rc = SCESTATUS_SUCCESS;
  1007. } else if ( rc != SCESTATUS_SUCCESS) {
  1008. break;
  1009. }
  1010. }
  1011. }
  1012. if ( hSectionScp && pMergedList ) {
  1013. for ( pPriv=pMergedList; pPriv != NULL; pPriv = pPriv->Next ) {
  1014. //
  1015. // Process each privilege in the new list
  1016. // Update SCP with new value, don't care error
  1017. //
  1018. if ( pPriv->Status == SCE_STATUS_MISMATCH ) {
  1019. //
  1020. // this is in name format, convert it
  1021. //
  1022. rc = ScepWriteNameListValue(
  1023. lsaHandle,
  1024. hSectionScp,
  1025. pPriv->Name,
  1026. pPriv->AssignedTo,
  1027. SCE_WRITE_EMPTY_LIST, // no need to lookup | SCE_WRITE_CONVERT,
  1028. 0
  1029. );
  1030. rc = SCESTATUS_SUCCESS;
  1031. }
  1032. }
  1033. }
  1034. if ( hSectionScp ) {
  1035. SceJetCloseSection(&hSectionScp, TRUE);
  1036. }
  1037. SceJetCloseSection(&hSectionSmp, TRUE);
  1038. }
  1039. if ( lsaHandle ) {
  1040. LsaClose(lsaHandle);
  1041. }
  1042. return(rc);
  1043. }
  1044. DWORD
  1045. ScepNotifyGetDefaultGPOTemplateName(
  1046. UNICODE_STRING DnsDomainName,
  1047. IN BOOL bDomainPolicy,
  1048. IN DWORD dwInSetup,
  1049. OUT LPTSTR *pTemplateName
  1050. )
  1051. /*
  1052. Return the GPO template name to use
  1053. In NT4 upgrade, because DS is not created yet, a temporary file is used in
  1054. %windir%\security\filtemp.inf
  1055. In NT5 upgrade, because network is not running in setup (sysvol share is not
  1056. accessible), the GPO template is referenced with absolute path, e.g.
  1057. %windir%\sysvol\sysvol\<dns name>\.... If sysvol path can't be queried,
  1058. the temporary file as in NT4 case is used.
  1059. Outside setup when DS/network is running, the GPO template is referenced with
  1060. the DNS UNC path, e.g, \\<computername>\sysvol\<dns name>\...
  1061. */
  1062. {
  1063. if ( ( dwInSetup != SCEGPO_INSETUP_NT4 &&
  1064. ( DnsDomainName.Buffer == NULL ||
  1065. DnsDomainName.Length == 0)) ||
  1066. pTemplateName == NULL ) {
  1067. return(ERROR_INVALID_PARAMETER);
  1068. }
  1069. //
  1070. // we have to replace the first DNS name with computer name
  1071. // because it might point to a remote machine where
  1072. // we don't have write access.
  1073. //
  1074. TCHAR Buffer[MAX_PATH+1];
  1075. DWORD dSize=MAX_PATH;
  1076. PWSTR SysvolPath=NULL;
  1077. Buffer[0] = L'\0';
  1078. BOOL bDefaultToNT4 = FALSE;
  1079. if ( dwInSetup == SCEGPO_INSETUP_NT5 ) {
  1080. //
  1081. // query the sysvol path from netlogon\parameters\sysvol registry value
  1082. //
  1083. DWORD RegType;
  1084. DWORD rc = ScepRegQueryValue(HKEY_LOCAL_MACHINE,
  1085. L"System\\CurrentControlSet\\Services\\Netlogon\\Parameters",
  1086. L"Sysvol",
  1087. (PVOID *)&SysvolPath,
  1088. &RegType
  1089. );
  1090. if ( ERROR_SUCCESS != rc || SysvolPath == NULL || RegType != REG_SZ) {
  1091. bDefaultToNT4 = TRUE;
  1092. if ( SysvolPath ) {
  1093. ScepFree(SysvolPath);
  1094. SysvolPath = NULL;
  1095. }
  1096. }
  1097. }
  1098. if ( dwInSetup ) {
  1099. // get %windir% directory
  1100. GetSystemWindowsDirectory(Buffer, MAX_PATH);
  1101. } else {
  1102. // get computer name
  1103. GetComputerName(Buffer, &dSize);
  1104. }
  1105. Buffer[MAX_PATH] = L'\0';
  1106. dSize = wcslen(Buffer);
  1107. DWORD Len;
  1108. DWORD rc=ERROR_SUCCESS;
  1109. if ( dwInSetup == SCEGPO_INSETUP_NT4 ||
  1110. (dwInSetup == SCEGPO_INSETUP_NT5 && bDefaultToNT4) ) {
  1111. //
  1112. // in setup, use the temp GPO file name
  1113. //
  1114. Len = dSize + wcslen(TEXT("\\security\\filtemp.inf"));
  1115. *pTemplateName = (PWSTR)LocalAlloc(LPTR, (Len+2)*sizeof(TCHAR));
  1116. if ( *pTemplateName ) {
  1117. swprintf(*pTemplateName, L"%s\\security\\filtemp.inf\0", Buffer);
  1118. //
  1119. // create the registry value for post setup
  1120. //
  1121. ScepRegSetIntValue( HKEY_LOCAL_MACHINE,
  1122. SCE_ROOT_PATH,
  1123. TEXT("PolicyChangedInSetup"),
  1124. 1
  1125. );
  1126. } else {
  1127. rc = ERROR_NOT_ENOUGH_MEMORY;
  1128. }
  1129. return rc;
  1130. }
  1131. if ( dwInSetup ) {
  1132. //
  1133. // in NT5 setup upgrade, should use SysvolPath
  1134. //
  1135. dSize = wcslen(SysvolPath);
  1136. Len = dSize + 1;
  1137. } else {
  1138. Len = 2 + dSize + wcslen(TEXT("\\sysvol\\"));
  1139. }
  1140. Len += ( DnsDomainName.Length/sizeof(TCHAR) +
  1141. wcslen(TEXT("\\Policies\\{}\\Machine\\")) +
  1142. wcslen(GPTSCE_TEMPLATE) );
  1143. if ( bDomainPolicy ) {
  1144. Len += wcslen(STR_DEFAULT_DOMAIN_GPO_GUID);
  1145. } else {
  1146. Len += wcslen(STR_DEFAULT_DOMAIN_CONTROLLER_GPO_GUID);
  1147. }
  1148. PWSTR GpoTemplateName = (PWSTR)LocalAlloc(LPTR, (Len+2)*sizeof(TCHAR));
  1149. if ( GpoTemplateName ) {
  1150. DWORD indx=0;
  1151. if ( dwInSetup ) {
  1152. swprintf(GpoTemplateName, L"%s\\", SysvolPath);
  1153. indx = 1;
  1154. } else {
  1155. swprintf(GpoTemplateName, L"\\\\%s\\sysvol\\", Buffer);
  1156. indx = 10;
  1157. }
  1158. wcsncpy(GpoTemplateName+indx+dSize, DnsDomainName.Buffer, DnsDomainName.Length/2);
  1159. if ( bDomainPolicy ) {
  1160. swprintf(GpoTemplateName+indx+dSize+DnsDomainName.Length/2,
  1161. L"\\Policies\\{%s}\\Machine\\%s\0",
  1162. STR_DEFAULT_DOMAIN_GPO_GUID, GPTSCE_TEMPLATE );
  1163. } else {
  1164. swprintf(GpoTemplateName+indx+dSize+DnsDomainName.Length/2,
  1165. L"\\Policies\\{%s}\\Machine\\%s\0",
  1166. STR_DEFAULT_DOMAIN_CONTROLLER_GPO_GUID, GPTSCE_TEMPLATE );
  1167. }
  1168. if ( 0xFFFFFFFF == GetFileAttributes(GpoTemplateName) ) {
  1169. rc = ERROR_OBJECT_NOT_FOUND;
  1170. LocalFree(GpoTemplateName);
  1171. GpoTemplateName = NULL;
  1172. }
  1173. } else {
  1174. rc = ERROR_NOT_ENOUGH_MEMORY;
  1175. }
  1176. //
  1177. // free the buffers if it fails
  1178. //
  1179. if ( SysvolPath ) {
  1180. ScepFree(SysvolPath);
  1181. }
  1182. *pTemplateName = GpoTemplateName;
  1183. return rc;
  1184. }
  1185. DWORD
  1186. ScepNotifySaveNotifications(
  1187. IN PWSTR TemplateName,
  1188. IN SECURITY_DB_TYPE DbType,
  1189. IN SECURITY_DB_OBJECT_TYPE ObjectType,
  1190. IN SECURITY_DB_DELTA_TYPE DeltaType,
  1191. IN PSID ObjectSid OPTIONAL
  1192. )
  1193. {
  1194. if ( TemplateName == NULL ) {
  1195. return ERROR_INVALID_PARAMETER;
  1196. }
  1197. DWORD rc=ERROR_SUCCESS;
  1198. if ( SecurityDbLsa == DbType &&
  1199. SecurityDbObjectLsaPolicy == ObjectType ) {
  1200. //
  1201. // LSA policy changes
  1202. //
  1203. if ( !WritePrivateProfileString(L"Policies",
  1204. L"LsaPolicy",
  1205. L"1",
  1206. TemplateName
  1207. ) ) {
  1208. rc = GetLastError();
  1209. }
  1210. } else if ( SecurityDbSam == DbType &&
  1211. ObjectType != SecurityDbObjectSamUser &&
  1212. ObjectType != SecurityDbObjectSamGroup &&
  1213. ObjectType != SecurityDbObjectSamAlias ) {
  1214. //
  1215. // if it's not for deleted account, update the SAM policy section
  1216. //
  1217. if ( !WritePrivateProfileString(L"Policies",
  1218. L"SamPolicy",
  1219. L"1",
  1220. TemplateName
  1221. ) ) {
  1222. rc = GetLastError();
  1223. }
  1224. } else if ( ObjectSid &&
  1225. (SecurityDbLsa == DbType || SecurityDbSam == DbType ) ) {
  1226. //
  1227. // account policy is changed (user rights)
  1228. // get all privileges assigned to this account
  1229. //
  1230. DWORD dwPrivLowHeld=0, dwPrivHighHeld=0;
  1231. if ( DeltaType == SecurityDbDelete ) {
  1232. dwPrivLowHeld = 0;
  1233. dwPrivHighHeld = 0;
  1234. } else {
  1235. LSA_HANDLE lsaHandle=NULL;
  1236. NTSTATUS NtStatus = ScepOpenLsaPolicy(
  1237. POLICY_VIEW_LOCAL_INFORMATION |
  1238. POLICY_LOOKUP_NAMES,
  1239. &lsaHandle,
  1240. TRUE
  1241. );
  1242. if ( NT_SUCCESS(NtStatus) ) {
  1243. NtStatus = ScepGetAccountExplicitRight(
  1244. lsaHandle,
  1245. ObjectSid,
  1246. &dwPrivLowHeld,
  1247. &dwPrivHighHeld
  1248. );
  1249. LsaClose( lsaHandle );
  1250. }
  1251. }
  1252. PWSTR SidString=NULL;
  1253. if ( ConvertSidToStringSid(ObjectSid,
  1254. &SidString
  1255. ) &&
  1256. SidString ) {
  1257. TCHAR tmpBuf[40];
  1258. swprintf(tmpBuf, L"%d %d %d\0", (DWORD)DeltaType, dwPrivLowHeld, dwPrivHighHeld);
  1259. if ( !WritePrivateProfileString(L"Accounts",
  1260. SidString,
  1261. tmpBuf,
  1262. TemplateName
  1263. ) ) {
  1264. rc = GetLastError();
  1265. }
  1266. LocalFree(SidString);
  1267. } else {
  1268. rc = GetLastError();
  1269. }
  1270. }
  1271. return rc;
  1272. }
  1273. DWORD
  1274. ScepNotifyUpdateGPOVersion(
  1275. IN PWSTR GpoTemplateName,
  1276. IN BOOL bDomainPolicy
  1277. )
  1278. /*
  1279. Update the version # (in DS and gpt.ini) for machine policy change
  1280. property gPCMachineExtensionNames is not changed because security extension
  1281. guid should already be there (by default).
  1282. */
  1283. {
  1284. if ( GpoTemplateName == NULL ) {
  1285. return ERROR_INVALID_PARAMETER;
  1286. }
  1287. DWORD rc=ERROR_SUCCESS;
  1288. //
  1289. // get the current version from gpt.ini
  1290. //
  1291. // build full path of gpt.ini first
  1292. //
  1293. PWSTR pTemp = wcsstr( GpoTemplateName, L"\\Machine\\");
  1294. if ( pTemp == NULL ) {
  1295. return ERROR_INVALID_PARAMETER;
  1296. }
  1297. PWSTR pszVersionFile = (PWSTR)LocalAlloc(0, (pTemp-GpoTemplateName+wcslen(TEXT("\\gpt.ini"))+1)*sizeof(WCHAR));
  1298. if ( pszVersionFile == NULL ) {
  1299. return ERROR_NOT_ENOUGH_MEMORY;
  1300. }
  1301. wcsncpy(pszVersionFile, GpoTemplateName, (size_t)(pTemp-GpoTemplateName));
  1302. pszVersionFile[pTemp-GpoTemplateName] = L'\0';
  1303. wcscat(pszVersionFile, TEXT("\\gpt.ini"));
  1304. DWORD dwVersion = GetPrivateProfileInt(TEXT("General"), TEXT("Version"), 0, pszVersionFile);
  1305. if ( dwVersion == 0 ) {
  1306. //
  1307. // couldn't find version #, this is bad
  1308. //
  1309. rc = ERROR_FILE_NOT_FOUND;
  1310. } else {
  1311. //
  1312. // bind to DS, get DS root
  1313. //
  1314. PLDAP phLdap = ldap_open(NULL, LDAP_PORT);
  1315. if ( phLdap == NULL ) {
  1316. rc = ERROR_FILE_NOT_FOUND;
  1317. } else {
  1318. rc = ldap_bind_s(phLdap,
  1319. NULL,
  1320. NULL,
  1321. LDAP_AUTH_SSPI);
  1322. if ( rc == ERROR_SUCCESS ) {
  1323. LDAPMessage *Message = NULL; // for LDAP calls.
  1324. PWSTR Attribs[3]; // for LDAP calls.
  1325. LDAPMessage *Entry = NULL;
  1326. PWSTR DsRootName=NULL;
  1327. Attribs[0] = LDAP_OPATT_DEFAULT_NAMING_CONTEXT_W; // ntldap.h
  1328. Attribs[1] = NULL;
  1329. Attribs[2] = NULL;
  1330. rc = ldap_search_s(phLdap,
  1331. L"",
  1332. LDAP_SCOPE_BASE,
  1333. L"(objectClass=*)",
  1334. Attribs,
  1335. 0,
  1336. &Message);
  1337. if( rc == ERROR_SUCCESS ) {
  1338. //
  1339. // read the first entry.
  1340. // we did base level search, we have only one entry.
  1341. // Entry does not need to be freed (it is freed with the message)
  1342. //
  1343. Entry = ldap_first_entry(phLdap, Message);
  1344. if(Entry != NULL) {
  1345. PWSTR *Values = ldap_get_values(phLdap, Entry, Attribs[0]);
  1346. if(Values != NULL) {
  1347. DsRootName = (PWSTR)LocalAlloc(0, (wcslen(Values[0])+1)*sizeof(WCHAR));
  1348. if ( DsRootName ) {
  1349. wcscpy(DsRootName, Values[0]);
  1350. } else {
  1351. rc = ERROR_NOT_ENOUGH_MEMORY;
  1352. }
  1353. ldap_value_free(Values);
  1354. } else
  1355. rc = LdapMapErrorToWin32(phLdap->ld_errno);
  1356. } else
  1357. rc = LdapMapErrorToWin32(phLdap->ld_errno);
  1358. Entry = NULL;
  1359. }
  1360. //
  1361. // ldap_search can return failure and still allocate the buffer
  1362. //
  1363. if ( Message ) {
  1364. ldap_msgfree(Message);
  1365. Message = NULL;
  1366. }
  1367. if ( DsRootName ) {
  1368. //
  1369. // query version from DS, if failed, query version from gpt.ini
  1370. //
  1371. Attribs[0] = L"distinguishedName";
  1372. Attribs[1] = L"versionNumber";
  1373. Attribs[2] = NULL;
  1374. WCHAR szFilter[128];
  1375. if ( bDomainPolicy ) {
  1376. swprintf(szFilter, L"( &(objectClass=groupPolicyContainer)(cn={%s}) )", STR_DEFAULT_DOMAIN_GPO_GUID);
  1377. } else {
  1378. swprintf(szFilter, L"( &(objectClass=groupPolicyContainer)(cn={%s}) )", STR_DEFAULT_DOMAIN_CONTROLLER_GPO_GUID);
  1379. }
  1380. phLdap->ld_options = 0; // no chased referrel
  1381. rc = ldap_search_s(
  1382. phLdap,
  1383. DsRootName,
  1384. LDAP_SCOPE_SUBTREE,
  1385. szFilter,
  1386. Attribs,
  1387. 0,
  1388. &Message);
  1389. if( rc == ERROR_SUCCESS ) {
  1390. //
  1391. // read the first entry.
  1392. // we did base level search, we have only one entry.
  1393. // Entry does not need to be freed (it is freed with the message)
  1394. //
  1395. Entry = ldap_first_entry(phLdap, Message);
  1396. if(Entry != NULL) {
  1397. PWSTR *Values = ldap_get_values(phLdap, Entry, Attribs[0]);
  1398. if(Values != NULL) {
  1399. if ( Values[0] == NULL ) {
  1400. //
  1401. // unknown error.
  1402. //
  1403. rc = ERROR_FILE_NOT_FOUND;
  1404. } else {
  1405. PWSTR *pszVersions = ldap_get_values(phLdap, Entry, Attribs[1]);
  1406. if ( pszVersions && pszVersions[0] ) {
  1407. //
  1408. // this is the version number
  1409. //
  1410. dwVersion = _wtol(pszVersions[0]);
  1411. }
  1412. if ( pszVersions ) {
  1413. ldap_value_free(pszVersions);
  1414. }
  1415. //
  1416. // Value[0] is the base GPO name,
  1417. // now modify the version #
  1418. //
  1419. PLDAPMod rgMods[2];
  1420. LDAPMod Mod;
  1421. PWSTR rgpszVals[2];
  1422. WCHAR szVal[32];
  1423. USHORT uMachine, uUser;
  1424. //
  1425. // split the version # for machine and user
  1426. //
  1427. uUser = (USHORT) HIWORD(dwVersion);
  1428. uMachine = (USHORT) LOWORD(dwVersion);
  1429. dwVersion = (ULONG) MAKELONG (uMachine+1, uUser);
  1430. rgMods[0] = &Mod;
  1431. rgMods[1] = NULL;
  1432. memset(szVal, '\0', 32*2);
  1433. swprintf(szVal, L"%d", dwVersion);
  1434. rgpszVals[0] = szVal;
  1435. rgpszVals[1] = NULL;
  1436. //
  1437. // lets set version number back
  1438. //
  1439. Mod.mod_op = LDAP_MOD_REPLACE;
  1440. Mod.mod_values = rgpszVals;
  1441. Mod.mod_type = L"versionNumber";
  1442. //
  1443. // Now, we'll do the write
  1444. //
  1445. rc = ldap_modify_s(phLdap,
  1446. Values[0],
  1447. rgMods
  1448. );
  1449. if ( rc == ERROR_ALREADY_EXISTS )
  1450. rc = ERROR_SUCCESS;
  1451. if ( rc == ERROR_SUCCESS ) {
  1452. //
  1453. // update version in gpt.ini
  1454. //
  1455. WritePrivateProfileString (TEXT("General"), TEXT("Version"), szVal, pszVersionFile);
  1456. }
  1457. }
  1458. ldap_value_free(Values);
  1459. } else
  1460. rc = LdapMapErrorToWin32(phLdap->ld_errno);
  1461. } else
  1462. rc = LdapMapErrorToWin32(phLdap->ld_errno);
  1463. }
  1464. LocalFree(DsRootName);
  1465. //
  1466. // ldap_search can return failure and still allocate the buffer
  1467. //
  1468. if ( Message ) {
  1469. ldap_msgfree(Message);
  1470. Message = NULL;
  1471. }
  1472. }
  1473. }
  1474. ldap_unbind(phLdap);
  1475. }
  1476. }
  1477. LocalFree(pszVersionFile);
  1478. return rc;
  1479. }