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.

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