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.

1434 lines
36 KiB

  1. /*++
  2. Copyright (c) 1987-1997 Microsoft Corporation
  3. Module Name:
  4. polfiltr.cpp
  5. Abstract:
  6. Policy notification implementation to support down level API calls.
  7. This file implements the notification logic when down level APIs
  8. (LSA/SAM) are called by other apps to change security policies. The
  9. policy changes are written to LSA database or DS, and also they are
  10. required to be written to the policy storage on NT5 so policy
  11. propagation won't overwrite the settings.
  12. Environment:
  13. User mode only.
  14. Contains NT-specific code.
  15. Revision History:
  16. --*/
  17. //
  18. // Common include files.
  19. //
  20. #include "headers.h"
  21. #include "scerpc.h"
  22. #include "scesetup.h"
  23. #include "sceutil.h"
  24. #include "clntutil.h"
  25. #include "scedllrc.h"
  26. #include <ntrpcp.h>
  27. #include <ntsam.h>
  28. #include <dsrole.h>
  29. #include <sddl.h>
  30. //#include <gpedit.h>
  31. //#include <initguid.h>
  32. //#include <winldap.h>
  33. //#include <dsgetdc.h>
  34. #include <ntdsapi.h>
  35. #include <io.h>
  36. //#include "infp.h"
  37. #include <rpcasync.h>
  38. #pragma hdrstop
  39. extern HINSTANCE MyModuleHandle;
  40. //typedef DWORD (WINAPI *PFNDSGETDCNAME)(LPCTSTR, LPCTSTR, GUID *, LPCTSTR, ULONG, PDOMAIN_CONTROLLER_INFO *);
  41. typedef VOID (WINAPI *PFNDSROLEFREE)(PVOID);
  42. typedef DWORD (WINAPI *PFNDSROLEGETINFO)(LPCWSTR,DSROLE_PRIMARY_DOMAIN_INFO_LEVEL,PBYTE *);
  43. typedef struct _SCEP_NOTIFYARGS_NODE {
  44. LIST_ENTRY List;
  45. SECURITY_DB_TYPE DbType;
  46. SECURITY_DB_DELTA_TYPE DeltaType;
  47. SECURITY_DB_OBJECT_TYPE ObjectType;
  48. PSID ObjectSid;
  49. } SCEP_NOTIFYARGS_NODE, *PSCEP_NOTIFYARGS_NODE;
  50. static DSROLE_MACHINE_ROLE MachineRole;
  51. static BOOL bRoleQueried=FALSE;
  52. static ULONG DsRoleFlags=0;
  53. static PSID BuiltinDomainSid=NULL;
  54. CRITICAL_SECTION PolicyNotificationSync;
  55. static DWORD SceNotifyCount=0;
  56. static BOOL gSceNotificationThreadActive=FALSE;
  57. LIST_ENTRY ScepNotifyList;
  58. DWORD
  59. ScepNotifyWorkerThread(
  60. PVOID Ignored
  61. );
  62. DWORD
  63. ScepNotifySaveInPolicyStorage(
  64. IN SECURITY_DB_TYPE DbType,
  65. IN SECURITY_DB_DELTA_TYPE DeltaType,
  66. IN SECURITY_DB_OBJECT_TYPE ObjectType,
  67. IN PSID ObjectSid
  68. );
  69. DWORD
  70. ScepNotifySaveChangeInServer(
  71. IN SECURITY_DB_TYPE DbType,
  72. IN SECURITY_DB_DELTA_TYPE DeltaType,
  73. IN SECURITY_DB_OBJECT_TYPE ObjectType,
  74. IN PSID ObjectSid OPTIONAL,
  75. IN BOOL bDCGPO,
  76. IN DWORD ExplicitLowRight,
  77. IN DWORD ExplicitHighRight
  78. );
  79. DWORD
  80. ScepNotifyFailureLog(
  81. IN DWORD ErrCode,
  82. IN UINT idMsg,
  83. IN DWORD DbType,
  84. IN DWORD ObjectType,
  85. IN PWSTR Message
  86. );
  87. DWORD
  88. ScepNotificationRequest(
  89. PSCEP_NOTIFYARGS_NODE Node
  90. );
  91. DWORD
  92. ScepSendNotificationNodeToServer(
  93. PSCEP_NOTIFYARGS_NODE Node
  94. );
  95. NTSTATUS
  96. WINAPI
  97. SceNotifyPolicyDelta (
  98. IN SECURITY_DB_TYPE DbType,
  99. IN SECURITY_DB_DELTA_TYPE DeltaType,
  100. IN SECURITY_DB_OBJECT_TYPE ObjectType,
  101. IN PSID ObjectSid
  102. )
  103. /*++
  104. Routine Description:
  105. This function is called by the LSA after each change is
  106. made to the LSA database (SAM calls DeltaNotify - not this funtion).
  107. The LSA describes the type of object that is modified, the type of modification
  108. made on the object, etc.
  109. This information will be used to query the system settings and store in
  110. the policy storage (GPO on DC, LPO on workstation/server).
  111. Arguments:
  112. DbType - Type of the database that has been modified.
  113. DeltaType - The type of modification that has been made on the object.
  114. ObjectType - The type of object that has been modified.
  115. ObjectSid - The SID of the object that has been modified.
  116. Return Value:
  117. STATUS_SUCCESS - The Service completed successfully.
  118. --*/
  119. {
  120. DWORD dwPolicyFilterOff=0;
  121. ScepRegQueryIntValue(
  122. HKEY_LOCAL_MACHINE,
  123. SCE_ROOT_PATH,
  124. TEXT("PolicyFilterOff"),
  125. &dwPolicyFilterOff
  126. );
  127. if ( dwPolicyFilterOff ) {
  128. return STATUS_SUCCESS;
  129. }
  130. if ( DbType == SecurityDbLsa ) {
  131. //
  132. // LSA policy changes
  133. //
  134. if ( ObjectType != SecurityDbObjectLsaPolicy &&
  135. ObjectType != SecurityDbObjectLsaAccount ) {
  136. return STATUS_SUCCESS;
  137. }
  138. } else if ( DbType == SecurityDbSam ) {
  139. //
  140. // SAM policy changes is supported by the standard
  141. // SAM change notification mechanism
  142. // this parameter here is not used (should not be
  143. // called by LSA
  144. //
  145. return STATUS_SUCCESS;
  146. } else {
  147. //
  148. // unknown database, do nothing.
  149. //
  150. return STATUS_SUCCESS;
  151. }
  152. //
  153. // Map object type and delta type to NetlogonDeltaType
  154. //
  155. switch( ObjectType ) {
  156. case SecurityDbObjectLsaPolicy:
  157. switch (DeltaType) {
  158. case SecurityDbNew:
  159. case SecurityDbChange:
  160. break;
  161. // unknown delta type
  162. default:
  163. return STATUS_SUCCESS;
  164. }
  165. break;
  166. case SecurityDbObjectLsaAccount:
  167. switch (DeltaType) {
  168. case SecurityDbNew:
  169. case SecurityDbChange:
  170. case SecurityDbDelete:
  171. break;
  172. // unknown delta type
  173. default:
  174. return STATUS_SUCCESS;
  175. }
  176. if ( ObjectSid == NULL ) {
  177. // for privileges, must have a Sid
  178. return STATUS_SUCCESS;
  179. }
  180. break;
  181. default:
  182. // unknown object type
  183. // SAM policy is filtered in DeltaNotify routine
  184. //
  185. return STATUS_SUCCESS;
  186. }
  187. //
  188. // Save the change to SCE policy storage
  189. //
  190. (VOID) ScepNotifySaveInPolicyStorage(DbType,
  191. DeltaType,
  192. ObjectType,
  193. ObjectSid
  194. );
  195. return STATUS_SUCCESS;
  196. }
  197. DWORD
  198. ScepNotifySaveInPolicyStorage(
  199. IN SECURITY_DB_TYPE DbType,
  200. IN SECURITY_DB_DELTA_TYPE DeltaType,
  201. IN SECURITY_DB_OBJECT_TYPE ObjectType,
  202. IN PSID ObjectSid
  203. )
  204. {
  205. DWORD rc=ERROR_SUCCESS;
  206. if ( !bRoleQueried ||
  207. MachineRole == DsRole_RoleBackupDomainController ||
  208. MachineRole == DsRole_RolePrimaryDomainController ) {
  209. } else {
  210. //
  211. // no filter on non-DCs
  212. //
  213. return(rc);
  214. }
  215. //
  216. // make a structure to pass into the new asynchronous thread
  217. //
  218. SCEP_NOTIFYARGS_NODE *pEA = (SCEP_NOTIFYARGS_NODE *)LocalAlloc(LPTR, sizeof(SCEP_NOTIFYARGS_NODE));
  219. if ( pEA ) {
  220. pEA->DbType = DbType;
  221. pEA->DeltaType = DeltaType;
  222. pEA->ObjectType = ObjectType;
  223. if ( ObjectSid ) {
  224. //
  225. // need to make a new buffer for this SID because once it's returned
  226. // it will be freed.
  227. //
  228. DWORD Len = RtlLengthSid(ObjectSid);
  229. pEA->ObjectSid = (PSID)LocalAlloc(0, Len+1);
  230. if ( pEA->ObjectSid ) {
  231. RtlCopySid (
  232. Len+1,
  233. pEA->ObjectSid,
  234. ObjectSid
  235. );
  236. } else {
  237. rc = ERROR_NOT_ENOUGH_MEMORY;
  238. LocalFree(pEA);
  239. }
  240. } else {
  241. pEA->ObjectSid = NULL;
  242. }
  243. } else {
  244. rc = ERROR_NOT_ENOUGH_MEMORY;
  245. }
  246. if ( ERROR_SUCCESS == rc ) {
  247. //
  248. // create another thread to call to engine
  249. // (to make sure that the current LSA call is not blocked)
  250. // because in engine, it quries the same change using LSA apis.
  251. //
  252. // note, when this is called, LSA is not impersonating
  253. // so the current calling context is running under system
  254. // context. No need (no way) to impersonate.
  255. //
  256. rc = ScepNotificationRequest(pEA);
  257. if ( ERROR_SUCCESS != rc ) {
  258. //
  259. // error occurs to queue the work item, the memory won't
  260. // be freed by the thread, so free it here
  261. //
  262. if ( pEA->ObjectSid ) {
  263. LocalFree(pEA->ObjectSid);
  264. }
  265. LocalFree(pEA);
  266. ScepNotifyFailureLog(rc,
  267. IDS_ERROR_CREATE_THREAD,
  268. (DWORD)DbType,
  269. (DWORD)ObjectType,
  270. NULL
  271. );
  272. }
  273. } else {
  274. ScepNotifyFailureLog(rc,
  275. IDS_ERROR_CREATE_THREAD_PARAM,
  276. (DWORD)DbType,
  277. (DWORD)ObjectType,
  278. NULL
  279. );
  280. }
  281. return rc;
  282. }
  283. DWORD
  284. ScepNotificationRequest(
  285. PSCEP_NOTIFYARGS_NODE Node
  286. )
  287. {
  288. BOOL Ret = TRUE ;
  289. DWORD rCode = ERROR_SUCCESS;
  290. //
  291. // Increment the notification count
  292. //
  293. EnterCriticalSection(&PolicyNotificationSync);
  294. SceNotifyCount++;
  295. if ( gSceNotificationThreadActive == FALSE )
  296. {
  297. Ret = QueueUserWorkItem( ScepNotifyWorkerThread, NULL, 0 );
  298. }
  299. if ( Ret )
  300. {
  301. InsertTailList( &ScepNotifyList, &Node->List );
  302. // ScepNotifyFailureLog(0, 0, SceNotifyCount, 0, L"Add the request");
  303. } else {
  304. rCode = GetLastError();
  305. //
  306. // decrement the count
  307. //
  308. if ( SceNotifyCount > 0 ) SceNotifyCount--;
  309. }
  310. LeaveCriticalSection(&PolicyNotificationSync);
  311. return rCode ;
  312. }
  313. DWORD
  314. ScepNotifyFailureLog(
  315. IN DWORD ErrCode,
  316. IN UINT idMsg,
  317. IN DWORD DbType,
  318. IN DWORD ObjectType,
  319. IN PWSTR Message
  320. )
  321. {
  322. //
  323. // build the log file name %windir%\security\logs\Notify.log
  324. //
  325. WCHAR LogName[MAX_PATH+51];
  326. LogName[0] = L'\0';
  327. GetSystemWindowsDirectory(LogName, MAX_PATH);
  328. LogName[MAX_PATH] = L'\0';
  329. wcscat(LogName, L"\\security\\logs\\notify.log\0");
  330. HANDLE hFile = CreateFile(LogName,
  331. GENERIC_WRITE,
  332. FILE_SHARE_READ,
  333. NULL,
  334. OPEN_ALWAYS,
  335. FILE_ATTRIBUTE_NORMAL,
  336. NULL);
  337. if (hFile != INVALID_HANDLE_VALUE) {
  338. DWORD dwBytesWritten;
  339. SetFilePointer (hFile, 0, NULL, FILE_BEGIN);
  340. CHAR TmpBuf[3];
  341. TmpBuf[0] = (CHAR)0xFF;
  342. TmpBuf[1] = (CHAR)0xFE;
  343. TmpBuf[2] = '\0';
  344. WriteFile (hFile, (LPCVOID)TmpBuf, 2,
  345. &dwBytesWritten,
  346. NULL);
  347. SetFilePointer (hFile, 0, NULL, FILE_END);
  348. //
  349. // print a time stamp
  350. //
  351. LARGE_INTEGER CurrentTime;
  352. LARGE_INTEGER SysTime;
  353. TIME_FIELDS TimeFields;
  354. NTSTATUS NtStatus;
  355. NtStatus = NtQuerySystemTime(&SysTime);
  356. RtlSystemTimeToLocalTime (&SysTime,&CurrentTime);
  357. if ( NT_SUCCESS(NtStatus) &&
  358. (CurrentTime.LowPart != 0 || CurrentTime.HighPart != 0) ) {
  359. memset(&TimeFields, 0, sizeof(TIME_FIELDS));
  360. RtlTimeToTimeFields (
  361. &CurrentTime,
  362. &TimeFields
  363. );
  364. if ( TimeFields.Month > 0 && TimeFields.Month <= 12 &&
  365. TimeFields.Day > 0 && TimeFields.Day <= 31 &&
  366. TimeFields.Year > 1600 ) {
  367. ScepWriteVariableUnicodeLog(hFile, TRUE,
  368. L"\r\n----------------%02d/%02d/%04d %02d:%02d:%02d",
  369. TimeFields.Month,
  370. TimeFields.Day,
  371. TimeFields.Year,
  372. TimeFields.Hour,
  373. TimeFields.Minute,
  374. TimeFields.Second);
  375. } else {
  376. ScepWriteVariableUnicodeLog(hFile, TRUE,
  377. L"\r\n----------------%08x 08x",
  378. CurrentTime.HighPart,
  379. CurrentTime.LowPart);
  380. }
  381. } else {
  382. ScepWriteSingleUnicodeLog(hFile, TRUE, L"\r\n----------------Unknown time");
  383. }
  384. //
  385. // print operation status code
  386. //
  387. if ( ErrCode ) {
  388. ScepWriteVariableUnicodeLog(hFile, FALSE,
  389. L"Thread %x\tError=%d",
  390. GetCurrentThreadId(),
  391. ErrCode
  392. );
  393. } else {
  394. ScepWriteVariableUnicodeLog(hFile, FALSE,
  395. L"Thread %x\t",
  396. GetCurrentThreadId()
  397. );
  398. }
  399. //
  400. // operation type
  401. //
  402. if (Message ) {
  403. swprintf(LogName, L"\t%x\0",DbType);
  404. ScepWriteSingleUnicodeLog(hFile, FALSE, LogName);
  405. } else {
  406. switch (DbType) {
  407. case SecurityDbLsa:
  408. ScepWriteSingleUnicodeLog(hFile, FALSE, L"\tLSA");
  409. break;
  410. case SecurityDbSam:
  411. ScepWriteSingleUnicodeLog(hFile, FALSE, L"\tSAM");
  412. break;
  413. default:
  414. ScepWriteSingleUnicodeLog(hFile, FALSE, L"\tUnknown");
  415. break;
  416. }
  417. }
  418. //
  419. // print object type
  420. //
  421. if (Message ) {
  422. swprintf(LogName, L"\t%x\0",ObjectType);
  423. ScepWriteSingleUnicodeLog(hFile, FALSE, LogName);
  424. } else {
  425. switch (ObjectType) {
  426. case SecurityDbObjectLsaPolicy:
  427. ScepWriteSingleUnicodeLog(hFile, FALSE, L"\tPolicy");
  428. break;
  429. case SecurityDbObjectLsaAccount:
  430. ScepWriteSingleUnicodeLog(hFile, FALSE, L"\tAccount");
  431. break;
  432. case SecurityDbObjectSamDomain:
  433. ScepWriteSingleUnicodeLog(hFile, FALSE, L"\tDomain");
  434. break;
  435. case SecurityDbObjectSamUser:
  436. case SecurityDbObjectSamGroup:
  437. case SecurityDbObjectSamAlias:
  438. ScepWriteSingleUnicodeLog(hFile, FALSE, L"\tAccount");
  439. break;
  440. default:
  441. ScepWriteSingleUnicodeLog(hFile, FALSE, L"\tUnknown");
  442. break;
  443. }
  444. }
  445. //
  446. // load message
  447. // print the name(s)
  448. //
  449. ScepWriteSingleUnicodeLog(hFile, FALSE, L"\t");
  450. if (idMsg != 0) {
  451. LogName[0] = L'\0';
  452. LoadString (MyModuleHandle, idMsg, LogName, MAX_PATH);
  453. ScepWriteSingleUnicodeLog(hFile, TRUE, LogName);
  454. } else if (Message ) {
  455. ScepWriteSingleUnicodeLog(hFile, FALSE, Message);
  456. }
  457. CloseHandle (hFile);
  458. } else {
  459. return(GetLastError());
  460. }
  461. return(ERROR_SUCCESS);
  462. }
  463. DWORD
  464. ScepNotifyWorkerThread(
  465. PVOID Ignored
  466. )
  467. {
  468. PSCEP_NOTIFYARGS_NODE Node;
  469. PLIST_ENTRY List ;
  470. DWORD rc=0;
  471. EnterCriticalSection(&PolicyNotificationSync);
  472. //
  473. // if there is already a work thread on the notification, just return
  474. //
  475. if ( gSceNotificationThreadActive )
  476. {
  477. LeaveCriticalSection(&PolicyNotificationSync);
  478. return 0 ;
  479. }
  480. //
  481. // set the flag to be active
  482. //
  483. gSceNotificationThreadActive = TRUE ;
  484. // count is incremented in the main thread when the item is queued.
  485. // it may be before or after this thread.
  486. // InitializeEvents will check if the event is already initialized
  487. (void) InitializeEvents(L"SceCli");
  488. while ( !IsListEmpty( &ScepNotifyList ) )
  489. {
  490. List = RemoveHeadList( &ScepNotifyList );
  491. LeaveCriticalSection(&PolicyNotificationSync);
  492. //
  493. // get the node
  494. //
  495. Node = CONTAINING_RECORD( List, SCEP_NOTIFYARGS_NODE, List );
  496. rc = ScepSendNotificationNodeToServer( Node );
  497. EnterCriticalSection(&PolicyNotificationSync);
  498. //
  499. // decrement the global count
  500. //
  501. if ( SceNotifyCount > 0 )
  502. SceNotifyCount--;
  503. // ScepNotifyFailureLog(0, 0, SceNotifyCount, rc, L"Send over to server");
  504. }
  505. gSceNotificationThreadActive = FALSE ;
  506. //
  507. // only shutdown events when there is no pending notification
  508. //
  509. if ( SceNotifyCount == 0 )
  510. (void) ShutdownEvents();
  511. LeaveCriticalSection(&PolicyNotificationSync);
  512. return 0 ;
  513. }
  514. DWORD
  515. ScepSendNotificationNodeToServer(
  516. PSCEP_NOTIFYARGS_NODE Node
  517. )
  518. {
  519. DWORD rc=ERROR_SUCCESS;
  520. //
  521. // get machine role. If it's a DC, policy is saved to
  522. // the group policy object; if it's a server or workstation
  523. // policy is saved into the local SCE database.
  524. //
  525. if ( !bRoleQueried ) {
  526. rc = ScepGetDomainRoleInfo(&MachineRole, &DsRoleFlags, NULL);
  527. if( ERROR_SUCCESS == rc)
  528. {
  529. bRoleQueried = TRUE;
  530. }
  531. }
  532. //
  533. // we don't check for error because we
  534. // default to DsRole_RoleStandaloneWorkstation
  535. //
  536. if (Node->DbType == SecurityDbSam &&
  537. Node->ObjectType == SecurityDbObjectSamDomain &&
  538. Node->DeltaType != SecurityDbDelete &&
  539. DsRole_RoleBackupDomainController == MachineRole) {
  540. // ANZ hotfix
  541. //
  542. // do not filter SAM domain policies on BDCs, except for delete notifications
  543. //
  544. DbgPrint("\n Dropping SAM notification on BDCs\n");
  545. goto Exit;
  546. }
  547. //
  548. // when policy propagates, SAM notifications should be blocked
  549. // because policy might change SAM policies.
  550. //
  551. //
  552. // if event is not openable, allow the notification to go through
  553. // (since at reboot, downlevel APIs may trigger SAM notifications before
  554. // SCE server has started where the event is created)
  555. //
  556. if (rc != ERROR_SUCCESS ) {
  557. //
  558. // This isn't supposed to happen.
  559. // if it really happens, assuming it's a workstation/server
  560. //
  561. MachineRole = DsRole_RoleStandaloneWorkstation;
  562. LogEvent(MyModuleHandle,
  563. STATUS_SEVERITY_WARNING,
  564. SCEEVENT_WARNING_MACHINE_ROLE,
  565. IDS_ERROR_GET_ROLE,
  566. rc
  567. );
  568. }
  569. //
  570. // policy filter shouldn't run on non-DCs.
  571. //
  572. if ( MachineRole == DsRole_RoleBackupDomainController ||
  573. MachineRole == DsRole_RolePrimaryDomainController ) {
  574. //
  575. // if dcpromo upgrade in progress, any account policy
  576. // change should be ignored (because the SAM hive is temperatory)
  577. // any privilege change for account domain accounts (not well
  578. // known, and not builtin) should also be ignored.
  579. //
  580. if ( !(DsRoleFlags & DSROLE_UPGRADE_IN_PROGRESS) ||
  581. ( ( Node->DbType != SecurityDbSam ) &&
  582. ( ( Node->ObjectType != SecurityDbObjectLsaAccount ) ||
  583. !ScepIsSidFromAccountDomain( Node->ObjectSid ) ) ) ) {
  584. //
  585. // ignore any policy changes within dcpromo upgrade
  586. //
  587. // domain controllers, write to the default GPOs
  588. //
  589. rc = ScepNotifySaveChangeInServer(
  590. Node->DbType,
  591. Node->DeltaType,
  592. Node->ObjectType,
  593. Node->ObjectSid,
  594. TRUE,
  595. 0,
  596. 0
  597. );
  598. if ( ERROR_SUCCESS != rc &&
  599. RPC_S_SERVER_UNAVAILABLE != rc ) {
  600. LogEvent(MyModuleHandle,
  601. STATUS_SEVERITY_ERROR,
  602. SCEEVENT_ERROR_POLICY_QUEUE,
  603. IDS_ERROR_SAVE_POLICY_GPO,
  604. rc
  605. );
  606. }
  607. }
  608. } // turn off policy filter for non-DCs
  609. Exit:
  610. if ( Node->ObjectSid ) {
  611. LocalFree(Node->ObjectSid);
  612. }
  613. LocalFree(Node);
  614. return rc;
  615. }
  616. DWORD
  617. ScepNotifySaveChangeInServer(
  618. IN SECURITY_DB_TYPE DbType,
  619. IN SECURITY_DB_DELTA_TYPE DeltaType,
  620. IN SECURITY_DB_OBJECT_TYPE ObjectType,
  621. IN PSID ObjectSid OPTIONAL,
  622. IN BOOL bDCGPO,
  623. IN DWORD ExplicitLowRight,
  624. IN DWORD ExplicitHighRight
  625. )
  626. {
  627. //
  628. // call RPC interface to the server where query and set the changes
  629. // to the template or to the database
  630. //
  631. handle_t binding_h;
  632. NTSTATUS NtStatus;
  633. DWORD rc;
  634. //
  635. // RPC bind to the server (secure is not required)
  636. //
  637. NtStatus = ScepBindRpc(
  638. NULL,
  639. L"scerpc",
  640. 0,
  641. &binding_h
  642. );
  643. rc = RtlNtStatusToDosError(NtStatus);
  644. if (NT_SUCCESS(NtStatus)){
  645. RpcTryExcept {
  646. //
  647. // send the changes to server side to determine
  648. // if and where to save it
  649. //
  650. if ( bDCGPO ) {
  651. rc = SceRpcNotifySaveChangesInGP(
  652. binding_h,
  653. (DWORD)DbType,
  654. (DWORD)DeltaType,
  655. (DWORD)ObjectType,
  656. (PSCEPR_SID)ObjectSid,
  657. ExplicitLowRight,
  658. ExplicitHighRight
  659. );
  660. } // else do not filter
  661. } RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
  662. //
  663. // get exception code (DWORD)
  664. //
  665. rc = RpcExceptionCode();
  666. } RpcEndExcept;
  667. //
  668. // Free the binding handle
  669. //
  670. RpcpUnbindRpc( binding_h );
  671. }
  672. return(rc);
  673. }
  674. DWORD
  675. ScepProcessPolicyFilterTempFiles(
  676. IN LPTSTR LogFileName OPTIONAL
  677. )
  678. {
  679. DWORD dwpPolicy=0;
  680. ScepRegQueryIntValue(
  681. HKEY_LOCAL_MACHINE,
  682. SCE_ROOT_PATH,
  683. TEXT("PolicyChangedInSetup"),
  684. (DWORD *)&dwpPolicy
  685. );
  686. if ( dwpPolicy ) {
  687. LogEventAndReport(MyModuleHandle,
  688. LogFileName,
  689. 0,
  690. 0,
  691. IDS_FILTER_AFTER_SETUP,
  692. L""
  693. );
  694. //
  695. // this is the reboot after setup, no need to detect if this is a DC
  696. // because the above reg value shouldn't be set for other product types
  697. //
  698. //
  699. // build the temp file name
  700. //
  701. TCHAR TmpFileName[MAX_PATH+50];
  702. memset(TmpFileName, '\0', (MAX_PATH+50)*sizeof(TCHAR));
  703. GetSystemWindowsDirectory(TmpFileName, MAX_PATH);
  704. lstrcat(TmpFileName, TEXT("\\security\\filtemp.inf"));
  705. INT iNotify = GetPrivateProfileInt( L"Policies",
  706. L"LsaPolicy",
  707. 0,
  708. TmpFileName
  709. );
  710. if ( iNotify == 1 ) {
  711. //
  712. // Lsa policy is changed in setup
  713. //
  714. LogEventAndReport(MyModuleHandle,
  715. LogFileName,
  716. 0,
  717. 0,
  718. IDS_LSA_CHANGED_IN_SETUP,
  719. L""
  720. );
  721. ScepNotifySaveChangeInServer(
  722. SecurityDbLsa,
  723. SecurityDbChange,
  724. SecurityDbObjectLsaPolicy,
  725. NULL,
  726. TRUE,
  727. 0,
  728. 0
  729. );
  730. }
  731. iNotify = GetPrivateProfileInt( L"Policies",
  732. L"SamPolicy",
  733. 0,
  734. TmpFileName
  735. );
  736. if ( iNotify == 1 ) {
  737. //
  738. // SAM policy is changed in setup
  739. //
  740. LogEventAndReport(MyModuleHandle,
  741. LogFileName,
  742. 0,
  743. 0,
  744. IDS_SAM_CHANGED_IN_SETUP,
  745. L""
  746. );
  747. ScepNotifySaveChangeInServer(
  748. SecurityDbSam,
  749. SecurityDbChange,
  750. SecurityDbObjectSamDomain,
  751. NULL,
  752. TRUE,
  753. 0,
  754. 0
  755. );
  756. }
  757. //
  758. // process all the accounts for user right changes
  759. //
  760. DWORD nSize;
  761. DWORD rLen=0;
  762. PWSTR SidBuffer = NULL;
  763. iNotify = 1;
  764. do {
  765. if ( SidBuffer ) {
  766. LocalFree(SidBuffer);
  767. }
  768. iNotify++;
  769. nSize = MAX_PATH*iNotify;
  770. SidBuffer = (PWSTR)LocalAlloc(0, nSize*sizeof(TCHAR));
  771. if ( SidBuffer ) {
  772. SidBuffer[0] = L'\0';
  773. SidBuffer[1] = L'\0';
  774. rLen = GetPrivateProfileSection(
  775. L"Accounts",
  776. SidBuffer,
  777. nSize,
  778. TmpFileName
  779. );
  780. } else {
  781. rLen = 0;
  782. }
  783. } while ( rLen == nSize - 2 );
  784. //
  785. // find accounts, search for the '=' sign
  786. //
  787. PWSTR pStart = SidBuffer;
  788. PWSTR pTemp, pTemp2;
  789. PSID ObjectSid=NULL;
  790. while ( pStart && pStart[0] != L'\0' ) {
  791. pTemp = wcschr(pStart, L'=');
  792. if ( pTemp ) {
  793. *pTemp = L'\0';
  794. LogEventAndReport(MyModuleHandle,
  795. LogFileName,
  796. 0,
  797. 0,
  798. 0,
  799. pStart
  800. );
  801. if ( ConvertStringSidToSid(
  802. pStart,
  803. &ObjectSid
  804. ) ) {
  805. nSize = pTemp[1] - L'0';
  806. rLen = _wtol(pTemp+3);
  807. DWORD dwHigh=0;
  808. // search for the high value
  809. pTemp2 = wcschr(pTemp+3, L' ');
  810. if ( pTemp2 ) {
  811. dwHigh = _wtol(pTemp2+1);
  812. }
  813. LogEventAndReport(MyModuleHandle,
  814. LogFileName,
  815. 0,
  816. 0,
  817. IDS_FILTER_NOTIFY_SERVER,
  818. L""
  819. );
  820. ScepNotifySaveChangeInServer(
  821. SecurityDbLsa,
  822. (SECURITY_DB_DELTA_TYPE)nSize,
  823. SecurityDbObjectLsaAccount,
  824. ObjectSid,
  825. TRUE,
  826. rLen,
  827. dwHigh
  828. );
  829. }
  830. if ( ObjectSid ) {
  831. LocalFree(ObjectSid);
  832. ObjectSid = NULL;
  833. }
  834. *pTemp = L'=';
  835. }
  836. pTemp = pStart + wcslen(pStart) + 1;
  837. pStart = pTemp;
  838. }
  839. if ( SidBuffer ) {
  840. LocalFree(SidBuffer);
  841. }
  842. }
  843. //
  844. // delete the key and the temp file
  845. // for debugging purpose, leave the file
  846. //
  847. ScepClearPolicyFilterTempFiles(TRUE);
  848. // ScepClearPolicyFilterTempFiles(FALSE);
  849. return ERROR_SUCCESS;
  850. }
  851. DWORD
  852. ScepClearPolicyFilterTempFiles(
  853. BOOL bClearFile
  854. )
  855. {
  856. if ( bClearFile ) {
  857. TCHAR Buffer[MAX_PATH+51];
  858. Buffer[0] = L'\0';
  859. GetSystemWindowsDirectory(Buffer, MAX_PATH);
  860. Buffer[MAX_PATH] = L'\0';
  861. wcscat(Buffer, L"\\security\\filtemp.inf\0");
  862. DeleteFile(Buffer);
  863. }
  864. //
  865. // delete the registry value
  866. //
  867. DWORD rc = ScepRegDeleteValue(
  868. HKEY_LOCAL_MACHINE,
  869. SCE_ROOT_PATH,
  870. TEXT("PolicyChangedInSetup")
  871. );
  872. if ( rc != ERROR_SUCCESS &&
  873. rc != ERROR_FILE_NOT_FOUND &&
  874. rc != ERROR_PATH_NOT_FOUND ) {
  875. // if can't delete the value, set the value to 0
  876. ScepRegSetIntValue( HKEY_LOCAL_MACHINE,
  877. SCE_ROOT_PATH,
  878. TEXT("PolicyChangedInSetup"),
  879. 0
  880. );
  881. }
  882. return ERROR_SUCCESS;
  883. }
  884. // *********************************************************
  885. // SAM policy change notifications
  886. // procedures required by SAM notify mechanism
  887. //
  888. // *********************************************************
  889. BOOLEAN
  890. WINAPI
  891. InitializeChangeNotify()
  892. {
  893. // inidicate this DLL support notifcation routines
  894. // nothing special to be initialized
  895. NTSTATUS NtStatus;
  896. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  897. NtStatus = RtlAllocateAndInitializeSid(
  898. &NtAuthority,
  899. 1,
  900. SECURITY_BUILTIN_DOMAIN_RID,
  901. 0, 0, 0, 0, 0, 0, 0,
  902. &BuiltinDomainSid
  903. );
  904. return(TRUE);
  905. }
  906. BOOL
  907. UninitializeChangeNotify()
  908. {
  909. if ( BuiltinDomainSid ) {
  910. RtlFreeSid(BuiltinDomainSid);
  911. BuiltinDomainSid = NULL;
  912. }
  913. return TRUE;
  914. }
  915. NTSTATUS
  916. WINAPI
  917. DeltaNotify(
  918. IN PSID DomainSid,
  919. IN SECURITY_DB_DELTA_TYPE DeltaType,
  920. IN SECURITY_DB_OBJECT_TYPE ObjectType,
  921. IN ULONG ObjectRid,
  922. IN PUNICODE_STRING ObjectName OPTIONAL,
  923. IN PLARGE_INTEGER ModifiedCount,
  924. IN PSAM_DELTA_DATA DeltaData OPTIONAL
  925. )
  926. /*
  927. Routine Description:
  928. SAM policy change notification routine. Prototype and procedure
  929. names are all required by SAM (see ntsam.h)
  930. Arguments:
  931. Similar to SceNotifyPolicyDelta
  932. Return:
  933. NT Status (should always return success)
  934. */
  935. {
  936. if ( DomainSid == NULL ) {
  937. return STATUS_SUCCESS;
  938. }
  939. //
  940. // we don't track other SAM policies except the domain
  941. // policy (password policy and account policy)
  942. //
  943. switch (DeltaType) {
  944. case SecurityDbNew:
  945. case SecurityDbChange:
  946. if ( ObjectType != SecurityDbObjectSamDomain )
  947. return STATUS_SUCCESS;
  948. break;
  949. case SecurityDbDelete:
  950. //
  951. // handle account deletion notifications
  952. //
  953. if ( ObjectType != SecurityDbObjectSamUser &&
  954. ObjectType != SecurityDbObjectSamGroup &&
  955. ObjectType != SecurityDbObjectSamAlias ) {
  956. return STATUS_SUCCESS;
  957. }
  958. break;
  959. default:
  960. // unknown delta type
  961. //
  962. return STATUS_SUCCESS;
  963. }
  964. if ( BuiltinDomainSid &&
  965. RtlEqualSid( DomainSid, BuiltinDomainSid ) ) {
  966. //
  967. // no policy to filter in the BUILTIN domain
  968. //
  969. return STATUS_SUCCESS;
  970. }
  971. // SAM filter and SCE SAM area policy propagation should be mutually exclusive
  972. //
  973. // only test (NOT wait) with timeout = 0 based on the event's state
  974. // if event is not set (server is in SAM policy prop config)
  975. // drop this change
  976. // else
  977. // continue filtering this SAM change
  978. //
  979. HANDLE hEventSamFilterPolicyPropSync = NULL;
  980. DWORD rc=ERROR_SUCCESS;
  981. hEventSamFilterPolicyPropSync = OpenEvent(
  982. SYNCHRONIZE,
  983. FALSE,
  984. SCEP_SAM_FILTER_POLICY_PROP_EVENT
  985. );
  986. if (hEventSamFilterPolicyPropSync) {
  987. rc = WaitForSingleObjectEx(
  988. hEventSamFilterPolicyPropSync,
  989. 0,
  990. FALSE
  991. );
  992. CloseHandle(hEventSamFilterPolicyPropSync);
  993. hEventSamFilterPolicyPropSync = NULL;
  994. if ( rc != WAIT_OBJECT_0 ) {
  995. //
  996. // we treat all other non-signalled return codes conservatively
  997. //
  998. DbgPrint("\n Dropping SAM notification because of Policy Propagation lock\n");
  999. return rc;
  1000. }
  1001. //
  1002. // event is signaled by server - policy prop SAM config is over
  1003. //
  1004. }
  1005. DWORD dwPolicyFilterOff=0;
  1006. ScepRegQueryIntValue(
  1007. HKEY_LOCAL_MACHINE,
  1008. SCE_ROOT_PATH,
  1009. TEXT("PolicyFilterOff"),
  1010. &dwPolicyFilterOff
  1011. );
  1012. if ( dwPolicyFilterOff ) {
  1013. return STATUS_SUCCESS;
  1014. }
  1015. PSID AccountSid=NULL;
  1016. if ( SecurityDbDelete == DeltaType ) {
  1017. //
  1018. // handle account deletion notifications
  1019. //
  1020. if ( !NT_SUCCESS(ScepDomainIdToSid( DomainSid, ObjectRid, &AccountSid) ) ) {
  1021. return STATUS_SUCCESS;
  1022. }
  1023. }
  1024. (VOID) ScepNotifySaveInPolicyStorage(SecurityDbSam,
  1025. DeltaType,
  1026. ObjectType,
  1027. AccountSid
  1028. );
  1029. if ( AccountSid ) {
  1030. ScepFree(AccountSid);
  1031. }
  1032. return STATUS_SUCCESS;
  1033. }
  1034. NTSTATUS
  1035. SceOpenPolicy()
  1036. /*
  1037. Description:
  1038. This function is called to determine if LSA policy can be opened for
  1039. exclusive access.
  1040. This function will check SCE policy notification count and see if there
  1041. is any pending notifications that have not been added to the queue on the server
  1042. Note when this function is called by LSA, the WritePolicySemaphore in LSA
  1043. has been locked for write so other writes can't modify any policy in this window.
  1044. Return Value:
  1045. STATUS_SUCCESS indicates the count is successfully checked and it's 0.
  1046. STATUS_TIMEOUT indicates the queue is not empty or it fails to check the queue.
  1047. */
  1048. {
  1049. //
  1050. // check the global count
  1051. //
  1052. NTSTATUS Status=STATUS_TIMEOUT;
  1053. DWORD cnt=0;
  1054. while ( TRUE ) {
  1055. EnterCriticalSection(&PolicyNotificationSync);
  1056. if ( SceNotifyCount == 0 ) {
  1057. //
  1058. // there is no pending notification
  1059. //
  1060. if ( STATUS_SUCCESS == Status ) {
  1061. //
  1062. // double check for the count
  1063. //
  1064. LeaveCriticalSection(&PolicyNotificationSync);
  1065. break;
  1066. } else {
  1067. Status = STATUS_SUCCESS;
  1068. }
  1069. } else
  1070. Status = STATUS_TIMEOUT;
  1071. LeaveCriticalSection(&PolicyNotificationSync);
  1072. cnt++;
  1073. if ( cnt > 10 ) { // timeout 1 second.
  1074. break;
  1075. }
  1076. Sleep(100); // sleep for .1 second
  1077. }
  1078. if ( STATUS_SUCCESS != Status ) {
  1079. ScepNotifyFailureLog(0,
  1080. 0,
  1081. SceNotifyCount,
  1082. (DWORD)Status,
  1083. L"SceOpenPolicy"
  1084. );
  1085. }
  1086. return Status;
  1087. }