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.

2006 lines
63 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. IN UNICODE_STRING DnsDomainName,
  1047. IN PWSTR ComputerName OPTIONAL,
  1048. IN BOOL bDomainPolicy,
  1049. IN DWORD dwInSetup,
  1050. OUT LPTSTR *pTemplateName
  1051. )
  1052. /*
  1053. Description:
  1054. This function builds and returns a full path Group Policy Template
  1055. name (gpttmpl.inf) in a specified GPO - default domain GPO or default
  1056. domain controller GPO.
  1057. In NT4 upgrade, because DS is not created yet, a temporary file is used in
  1058. %windir%\security\filtemp.inf
  1059. In NT5 upgrade, because network is not running in setup (sysvol share is not
  1060. accessible), the GPO template is referenced with absolute path, e.g.
  1061. %windir%\sysvol\sysvol\<dns name>\.... If sysvol path can't be queried,
  1062. the temporary file as in NT4 case is used.
  1063. Outside setup when DS/network is running, the GPO template is referenced
  1064. with the DNS UNC path, e.g, \\<computername>\sysvol\<dns name>\...
  1065. If ComputerName is passed in, the parameter will be used; otherwise, the
  1066. local computer name is queried and used.
  1067. Parameters:
  1068. DnsDomainName - Domain's DNS name used in the path
  1069. ComputerName - name for the computer to connect to
  1070. bDomainPolicy - TRUE = default domain GPO; FALSE = default domain controller GPO
  1071. dwInSetup - != 0 in setup (NT4 or NT5)
  1072. pTemplateName - the output template full path name
  1073. Return Value:
  1074. Win32 error
  1075. */
  1076. {
  1077. if ( ( dwInSetup != SCEGPO_INSETUP_NT4 &&
  1078. ( DnsDomainName.Buffer == NULL ||
  1079. DnsDomainName.Length == 0)) ||
  1080. pTemplateName == NULL ) {
  1081. return(ERROR_INVALID_PARAMETER);
  1082. }
  1083. //
  1084. // we have to replace the first DNS name with computer name
  1085. // because it might point to a remote machine where
  1086. // we don't have write access.
  1087. //
  1088. TCHAR Buffer[MAX_PATH+1];
  1089. DWORD dSize=MAX_PATH;
  1090. PWSTR SysvolPath=NULL;
  1091. Buffer[0] = L'\0';
  1092. BOOL bDefaultToNT4 = FALSE;
  1093. if ( dwInSetup == SCEGPO_INSETUP_NT5 ) {
  1094. //
  1095. // query the sysvol path from netlogon\parameters\sysvol registry value
  1096. //
  1097. DWORD RegType;
  1098. DWORD rc = ScepRegQueryValue(HKEY_LOCAL_MACHINE,
  1099. L"System\\CurrentControlSet\\Services\\Netlogon\\Parameters",
  1100. L"Sysvol",
  1101. (PVOID *)&SysvolPath,
  1102. &RegType,
  1103. NULL
  1104. );
  1105. if ( ERROR_SUCCESS != rc || SysvolPath == NULL || RegType != REG_SZ) {
  1106. //
  1107. // if fails to query the sysvol path, default to NT4 setup case
  1108. // where the changes are saved in the temp file
  1109. //
  1110. bDefaultToNT4 = TRUE;
  1111. if ( SysvolPath ) {
  1112. ScepFree(SysvolPath);
  1113. SysvolPath = NULL;
  1114. }
  1115. }
  1116. }
  1117. if ( dwInSetup == SCEGPO_INSETUP_NT5 ||
  1118. dwInSetup == SCEGPO_INSETUP_NT4 ) {
  1119. //
  1120. // temp file name is stored in %windir% directory
  1121. //
  1122. GetSystemWindowsDirectory(Buffer, MAX_PATH);
  1123. } else if ( ComputerName == NULL ) {
  1124. //
  1125. // get current computer name
  1126. //
  1127. GetComputerName(Buffer, &dSize);
  1128. } else {
  1129. //
  1130. // use the passed in computer name
  1131. //
  1132. wcscpy(Buffer, ComputerName);
  1133. }
  1134. Buffer[MAX_PATH] = L'\0';
  1135. dSize = wcslen(Buffer);
  1136. DWORD Len;
  1137. DWORD rc=ERROR_SUCCESS;
  1138. if ( dwInSetup == SCEGPO_INSETUP_NT4 ||
  1139. (dwInSetup == SCEGPO_INSETUP_NT5 && bDefaultToNT4) ) {
  1140. //
  1141. // in setup, use the temp GPO file name
  1142. //
  1143. Len = dSize + wcslen(TEXT("\\security\\filtemp.inf"));
  1144. *pTemplateName = (PWSTR)LocalAlloc(LPTR, (Len+2)*sizeof(TCHAR));
  1145. if ( *pTemplateName ) {
  1146. swprintf(*pTemplateName, L"%s\\security\\filtemp.inf\0", Buffer);
  1147. //
  1148. // create the registry value for post setup
  1149. //
  1150. ScepRegSetIntValue( HKEY_LOCAL_MACHINE,
  1151. SCE_ROOT_PATH,
  1152. TEXT("PolicyChangedInSetup"),
  1153. 1
  1154. );
  1155. } else {
  1156. rc = ERROR_NOT_ENOUGH_MEMORY;
  1157. }
  1158. return rc;
  1159. }
  1160. if ( dwInSetup == SCEGPO_INSETUP_NT5 ||
  1161. dwInSetup == SCEGPO_INSETUP_NT4 ) {
  1162. //
  1163. // in NT5 setup upgrade, should use SysvolPath
  1164. // SysvolPath should not be NULL when get here
  1165. // but let's check it to avoid prefix errors
  1166. //
  1167. if ( SysvolPath == NULL ) {
  1168. return ERROR_NOT_ENOUGH_MEMORY;
  1169. }
  1170. dSize = wcslen(SysvolPath);
  1171. Len = dSize + 1;
  1172. } else {
  1173. Len = 2 + dSize + wcslen(TEXT("\\sysvol\\"));
  1174. }
  1175. Len += ( DnsDomainName.Length/sizeof(TCHAR) +
  1176. wcslen(TEXT("\\Policies\\{}\\Machine\\")) +
  1177. wcslen(GPTSCE_TEMPLATE) );
  1178. if ( bDomainPolicy ) {
  1179. Len += wcslen(STR_DEFAULT_DOMAIN_GPO_GUID);
  1180. } else {
  1181. Len += wcslen(STR_DEFAULT_DOMAIN_CONTROLLER_GPO_GUID);
  1182. }
  1183. //
  1184. // allocate buffer for the final GPO name
  1185. //
  1186. PWSTR GpoTemplateName = (PWSTR)LocalAlloc(LPTR, (Len+2)*sizeof(TCHAR));
  1187. if ( GpoTemplateName ) {
  1188. DWORD indx=0;
  1189. if ( dwInSetup == SCEGPO_INSETUP_NT5 ||
  1190. dwInSetup == SCEGPO_INSETUP_NT4 ) {
  1191. swprintf(GpoTemplateName, L"%s\\", SysvolPath);
  1192. indx = 1;
  1193. } else {
  1194. swprintf(GpoTemplateName, L"\\\\%s\\sysvol\\", Buffer);
  1195. indx = 10;
  1196. }
  1197. wcsncpy(GpoTemplateName+indx+dSize, DnsDomainName.Buffer, DnsDomainName.Length/2);
  1198. if ( bDomainPolicy ) {
  1199. swprintf(GpoTemplateName+indx+dSize+DnsDomainName.Length/2,
  1200. L"\\Policies\\{%s}\\Machine\\%s\0",
  1201. STR_DEFAULT_DOMAIN_GPO_GUID, GPTSCE_TEMPLATE );
  1202. } else {
  1203. swprintf(GpoTemplateName+indx+dSize+DnsDomainName.Length/2,
  1204. L"\\Policies\\{%s}\\Machine\\%s\0",
  1205. STR_DEFAULT_DOMAIN_CONTROLLER_GPO_GUID, GPTSCE_TEMPLATE );
  1206. }
  1207. //
  1208. // check to see if the template exists
  1209. //
  1210. if ( SCEGPO_NOCHECK_EXISTENCE != dwInSetup ) {
  1211. if ( 0xFFFFFFFF == GetFileAttributes(GpoTemplateName) ) {
  1212. rc = ERROR_OBJECT_NOT_FOUND;
  1213. LocalFree(GpoTemplateName);
  1214. GpoTemplateName = NULL;
  1215. }
  1216. }
  1217. } else {
  1218. rc = ERROR_NOT_ENOUGH_MEMORY;
  1219. }
  1220. //
  1221. // free the buffers if it fails
  1222. //
  1223. if ( SysvolPath ) {
  1224. ScepFree(SysvolPath);
  1225. }
  1226. *pTemplateName = GpoTemplateName;
  1227. return rc;
  1228. }
  1229. DWORD
  1230. ScepNotifySaveNotifications(
  1231. IN PWSTR TemplateName,
  1232. IN SECURITY_DB_TYPE DbType,
  1233. IN SECURITY_DB_OBJECT_TYPE ObjectType,
  1234. IN SECURITY_DB_DELTA_TYPE DeltaType,
  1235. IN PSID ObjectSid OPTIONAL
  1236. )
  1237. {
  1238. if ( TemplateName == NULL ) {
  1239. return ERROR_INVALID_PARAMETER;
  1240. }
  1241. DWORD rc=ERROR_SUCCESS;
  1242. if ( SecurityDbLsa == DbType &&
  1243. SecurityDbObjectLsaPolicy == ObjectType ) {
  1244. //
  1245. // LSA policy changes
  1246. //
  1247. if ( !WritePrivateProfileString(L"Policies",
  1248. L"LsaPolicy",
  1249. L"1",
  1250. TemplateName
  1251. ) ) {
  1252. rc = GetLastError();
  1253. }
  1254. } else if ( SecurityDbSam == DbType &&
  1255. ObjectType != SecurityDbObjectSamUser &&
  1256. ObjectType != SecurityDbObjectSamGroup &&
  1257. ObjectType != SecurityDbObjectSamAlias ) {
  1258. //
  1259. // if it's not for deleted account, update the SAM policy section
  1260. //
  1261. if ( !WritePrivateProfileString(L"Policies",
  1262. L"SamPolicy",
  1263. L"1",
  1264. TemplateName
  1265. ) ) {
  1266. rc = GetLastError();
  1267. }
  1268. } else if ( ObjectSid &&
  1269. (SecurityDbLsa == DbType || SecurityDbSam == DbType ) ) {
  1270. //
  1271. // account policy is changed (user rights)
  1272. // get all privileges assigned to this account
  1273. //
  1274. DWORD dwPrivLowHeld=0, dwPrivHighHeld=0;
  1275. if ( DeltaType == SecurityDbDelete ) {
  1276. dwPrivLowHeld = 0;
  1277. dwPrivHighHeld = 0;
  1278. } else {
  1279. LSA_HANDLE lsaHandle=NULL;
  1280. NTSTATUS NtStatus = ScepOpenLsaPolicy(
  1281. POLICY_VIEW_LOCAL_INFORMATION |
  1282. POLICY_LOOKUP_NAMES,
  1283. &lsaHandle,
  1284. TRUE
  1285. );
  1286. if ( NT_SUCCESS(NtStatus) ) {
  1287. NtStatus = ScepGetAccountExplicitRight(
  1288. lsaHandle,
  1289. ObjectSid,
  1290. &dwPrivLowHeld,
  1291. &dwPrivHighHeld
  1292. );
  1293. LsaClose( lsaHandle );
  1294. }
  1295. }
  1296. PWSTR SidString=NULL;
  1297. if ( ConvertSidToStringSid(ObjectSid,
  1298. &SidString
  1299. ) &&
  1300. SidString ) {
  1301. TCHAR tmpBuf[40];
  1302. swprintf(tmpBuf, L"%d %d %d\0", (DWORD)DeltaType, dwPrivLowHeld, dwPrivHighHeld);
  1303. if ( !WritePrivateProfileString(L"Accounts",
  1304. SidString,
  1305. tmpBuf,
  1306. TemplateName
  1307. ) ) {
  1308. rc = GetLastError();
  1309. }
  1310. LocalFree(SidString);
  1311. } else {
  1312. rc = GetLastError();
  1313. }
  1314. }
  1315. return rc;
  1316. }
  1317. DWORD
  1318. ScepNotifyUpdateGPOVersion(
  1319. IN PWSTR GpoTemplateName,
  1320. IN BOOL bDomainPolicy
  1321. )
  1322. /*
  1323. Update the version # (in DS and gpt.ini) for machine policy change
  1324. property gPCMachineExtensionNames is not changed because security extension
  1325. guid should already be there (by default).
  1326. */
  1327. {
  1328. if ( GpoTemplateName == NULL ) {
  1329. return ERROR_INVALID_PARAMETER;
  1330. }
  1331. DWORD rc=ERROR_SUCCESS;
  1332. DWORD dwVersion = 0;
  1333. //
  1334. // check gpt.ini existance
  1335. //
  1336. // build full path of gpt.ini first
  1337. //
  1338. PWSTR pTemp = wcsstr( GpoTemplateName, L"\\Machine\\");
  1339. if ( pTemp == NULL ) {
  1340. return ERROR_INVALID_PARAMETER;
  1341. }
  1342. PWSTR pszVersionFile = (PWSTR)LocalAlloc(0, (pTemp-GpoTemplateName+wcslen(TEXT("\\gpt.ini"))+1)*sizeof(WCHAR));
  1343. if ( pszVersionFile == NULL ) {
  1344. return ERROR_NOT_ENOUGH_MEMORY;
  1345. }
  1346. wcsncpy(pszVersionFile, GpoTemplateName, (size_t)(pTemp-GpoTemplateName));
  1347. pszVersionFile[pTemp-GpoTemplateName] = L'\0';
  1348. wcscat(pszVersionFile, TEXT("\\gpt.ini"));
  1349. /*
  1350. DWORD dwVersion = GetPrivateProfileInt(TEXT("General"), TEXT("Version"), 0, pszVersionFile);
  1351. if ( dwVersion == 0 ) {
  1352. //
  1353. // couldn't find version #, this is bad
  1354. //
  1355. rc = ERROR_FILE_NOT_FOUND;
  1356. }
  1357. */
  1358. DWORD dwFileAttributes = GetFileAttributes(pszVersionFile);
  1359. if(INVALID_FILE_ATTRIBUTES == dwFileAttributes){
  1360. rc = GetLastError();
  1361. } else {
  1362. //
  1363. // bind to DS, get DS root
  1364. //
  1365. PLDAP phLdap = ldap_open(NULL, LDAP_PORT);
  1366. if ( phLdap == NULL ) {
  1367. rc = ERROR_FILE_NOT_FOUND;
  1368. } else {
  1369. rc = ldap_bind_s(phLdap,
  1370. NULL,
  1371. NULL,
  1372. LDAP_AUTH_SSPI);
  1373. if ( rc == ERROR_SUCCESS ) {
  1374. LDAPMessage *Message = NULL; // for LDAP calls.
  1375. PWSTR Attribs[3]; // for LDAP calls.
  1376. LDAPMessage *Entry = NULL;
  1377. PWSTR DsRootName=NULL;
  1378. Attribs[0] = LDAP_OPATT_DEFAULT_NAMING_CONTEXT_W; // ntldap.h
  1379. Attribs[1] = NULL;
  1380. Attribs[2] = NULL;
  1381. rc = ldap_search_s(phLdap,
  1382. L"",
  1383. LDAP_SCOPE_BASE,
  1384. L"(objectClass=*)",
  1385. Attribs,
  1386. 0,
  1387. &Message);
  1388. if( rc == ERROR_SUCCESS ) {
  1389. //
  1390. // read the first entry.
  1391. // we did base level search, we have only one entry.
  1392. // Entry does not need to be freed (it is freed with the message)
  1393. //
  1394. Entry = ldap_first_entry(phLdap, Message);
  1395. if(Entry != NULL) {
  1396. PWSTR *Values = ldap_get_values(phLdap, Entry, Attribs[0]);
  1397. if(Values != NULL) {
  1398. DsRootName = (PWSTR)LocalAlloc(0, (wcslen(Values[0])+1)*sizeof(WCHAR));
  1399. if ( DsRootName ) {
  1400. wcscpy(DsRootName, Values[0]);
  1401. } else {
  1402. rc = ERROR_NOT_ENOUGH_MEMORY;
  1403. }
  1404. ldap_value_free(Values);
  1405. } else
  1406. rc = LdapMapErrorToWin32(phLdap->ld_errno);
  1407. } else
  1408. rc = LdapMapErrorToWin32(phLdap->ld_errno);
  1409. Entry = NULL;
  1410. }
  1411. //
  1412. // ldap_search can return failure and still allocate the buffer
  1413. //
  1414. if ( Message ) {
  1415. ldap_msgfree(Message);
  1416. Message = NULL;
  1417. }
  1418. if ( DsRootName ) {
  1419. //
  1420. // query version from DS, if failed, query version from gpt.ini
  1421. //
  1422. Attribs[0] = L"distinguishedName";
  1423. Attribs[1] = L"versionNumber";
  1424. Attribs[2] = NULL;
  1425. WCHAR szFilter[128];
  1426. if ( bDomainPolicy ) {
  1427. swprintf(szFilter, L"( &(objectClass=groupPolicyContainer)(cn={%s}) )", STR_DEFAULT_DOMAIN_GPO_GUID);
  1428. } else {
  1429. swprintf(szFilter, L"( &(objectClass=groupPolicyContainer)(cn={%s}) )", STR_DEFAULT_DOMAIN_CONTROLLER_GPO_GUID);
  1430. }
  1431. phLdap->ld_options = 0; // no chased referrel
  1432. rc = ldap_search_s(
  1433. phLdap,
  1434. DsRootName,
  1435. LDAP_SCOPE_SUBTREE,
  1436. szFilter,
  1437. Attribs,
  1438. 0,
  1439. &Message);
  1440. if( rc == ERROR_SUCCESS ) {
  1441. //
  1442. // read the first entry.
  1443. // we did base level search, we have only one entry.
  1444. // Entry does not need to be freed (it is freed with the message)
  1445. //
  1446. Entry = ldap_first_entry(phLdap, Message);
  1447. if(Entry != NULL) {
  1448. PWSTR *Values = ldap_get_values(phLdap, Entry, Attribs[0]);
  1449. if(Values != NULL) {
  1450. if ( Values[0] == NULL ) {
  1451. //
  1452. // unknown error.
  1453. //
  1454. rc = ERROR_FILE_NOT_FOUND;
  1455. } else {
  1456. PWSTR *pszVersions = ldap_get_values(phLdap, Entry, Attribs[1]);
  1457. if ( pszVersions && pszVersions[0] ) {
  1458. //
  1459. // this is the version number
  1460. //
  1461. dwVersion = _wtol(pszVersions[0]);
  1462. }
  1463. if ( pszVersions ) {
  1464. ldap_value_free(pszVersions);
  1465. }
  1466. //
  1467. // Value[0] is the base GPO name,
  1468. // now modify the version #
  1469. //
  1470. PLDAPMod rgMods[2];
  1471. LDAPMod Mod;
  1472. PWSTR rgpszVals[2];
  1473. WCHAR szVal[32];
  1474. USHORT uMachine, uUser;
  1475. //
  1476. // split the version # for machine and user
  1477. //
  1478. uUser = (USHORT) HIWORD(dwVersion);
  1479. uMachine = (USHORT) LOWORD(dwVersion);
  1480. //
  1481. // increament version number and skip zero
  1482. // when it overflows and go to one.
  1483. // because zero is treated specially by
  1484. // the group policy engine and will lead
  1485. // to skip the GPO processing
  1486. //
  1487. uMachine++;
  1488. if(0 == uMachine)
  1489. uMachine++;
  1490. dwVersion = (ULONG) MAKELONG (uMachine, uUser);
  1491. rgMods[0] = &Mod;
  1492. rgMods[1] = NULL;
  1493. memset(szVal, '\0', 32*2);
  1494. swprintf(szVal, L"%d", dwVersion);
  1495. rgpszVals[0] = szVal;
  1496. rgpszVals[1] = NULL;
  1497. //
  1498. // lets set version number back
  1499. //
  1500. Mod.mod_op = LDAP_MOD_REPLACE;
  1501. Mod.mod_values = rgpszVals;
  1502. Mod.mod_type = L"versionNumber";
  1503. //
  1504. // Now, we'll do the write
  1505. //
  1506. rc = ldap_modify_s(phLdap,
  1507. Values[0],
  1508. rgMods
  1509. );
  1510. if ( rc == ERROR_ALREADY_EXISTS )
  1511. rc = ERROR_SUCCESS;
  1512. if ( rc == ERROR_SUCCESS ) {
  1513. //
  1514. // update version in gpt.ini
  1515. //
  1516. WritePrivateProfileString (TEXT("General"), TEXT("Version"), szVal, pszVersionFile);
  1517. }
  1518. }
  1519. ldap_value_free(Values);
  1520. } else
  1521. rc = LdapMapErrorToWin32(phLdap->ld_errno);
  1522. } else
  1523. rc = LdapMapErrorToWin32(phLdap->ld_errno);
  1524. }
  1525. LocalFree(DsRootName);
  1526. //
  1527. // ldap_search can return failure and still allocate the buffer
  1528. //
  1529. if ( Message ) {
  1530. ldap_msgfree(Message);
  1531. Message = NULL;
  1532. }
  1533. }
  1534. }
  1535. ldap_unbind(phLdap);
  1536. }
  1537. }
  1538. LocalFree(pszVersionFile);
  1539. return rc;
  1540. }