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.

2407 lines
61 KiB

  1. /*++
  2. Copyright (c) 1987-1997 Microsoft Corporation
  3. Module Name:
  4. changelg.c
  5. Abstract:
  6. Change Log implementation.
  7. This file implements the change log. It is isolated in this file
  8. because it has several restrictions.
  9. * The globals maintained by this module are initialized during
  10. netlogon.dll process attach. They are cleaned up netlogon.dll
  11. process detach.
  12. * These procedures are used by SAM, LSA, and the netlogon service.
  13. The LSA should be the first to load netlogon.dll. It should
  14. then immediately call I_NetNotifyRole before allowing SAM or the
  15. netlogon service to start.
  16. * These procedures cannot use any globals initialized by the netlogon
  17. service.
  18. Author:
  19. Ported from Lan Man 2.0
  20. Environment:
  21. User mode only.
  22. Contains NT-specific code.
  23. Requires ANSI C extensions: slash-slash comments, long external names.
  24. Revision History:
  25. 22-Jul-1991 (cliffv)
  26. Ported to NT. Converted to NT style.
  27. 02-Jan-1992 (madana)
  28. added support for builtin/multidomain replication.
  29. 04-Apr-1992 (madana)
  30. Added support for LSA replication.
  31. --*/
  32. //
  33. // Common include files.
  34. //
  35. #include "logonsrv.h" // Include files common to entire service
  36. #pragma hdrstop
  37. //
  38. // Include files specific to this .c file
  39. //
  40. #include <configp.h> // USE_WIN32_CONFIG (if defined), etc.
  41. //
  42. // Globals defining change log worker thread.
  43. //
  44. HANDLE NlGlobalChangeLogWorkerThreadHandle;
  45. BOOL NlGlobalChangeLogWorkerIsRunning;
  46. BOOL NlGlobalChangeLogNotifyBrowser;
  47. BOOL NlGlobalChangeLogNotifyBrowserIsRunning;
  48. BOOL
  49. IsChangeLogWorkerRunning(
  50. VOID
  51. );
  52. VOID
  53. NlChangeLogWorker(
  54. IN LPVOID ChangeLogWorkerParam
  55. )
  56. /*++
  57. Routine Description:
  58. This thread performs any long term operations that:
  59. A) must happen even though netlogon isn't up, and
  60. B) cannot happen in the context of an LSA or SAM notification.
  61. Arguments:
  62. None.
  63. Return Value:
  64. --*/
  65. {
  66. NET_API_STATUS NetStatus;
  67. NTSTATUS Status;
  68. LPWSTR NewDomainName;
  69. NlPrint((NL_CHANGELOG, "ChangeLogWorker Thread is starting \n"));
  70. //
  71. // Loop until there is no more work to do.
  72. //
  73. LOCK_CHANGELOG();
  74. for (;;) {
  75. //
  76. // Handle the domain being renamed.
  77. //
  78. if ( NlGlobalChangeLogNotifyBrowser ) {
  79. NlGlobalChangeLogNotifyBrowser = FALSE;
  80. NlGlobalChangeLogNotifyBrowserIsRunning = TRUE;
  81. UNLOCK_CHANGELOG();
  82. NetStatus = NetpGetDomainName( &NewDomainName );
  83. if ( NetStatus == NO_ERROR ) {
  84. //
  85. // Tell the bowser about the new domain name
  86. //
  87. Status = NlBrowserRenameDomain( NULL, NewDomainName );
  88. if ( !NT_SUCCESS(Status) ) {
  89. NlPrint(( NL_CRITICAL,
  90. "ChangeLogWorker: Browser won't rename domain: %lx\n",
  91. Status ));
  92. }
  93. //
  94. // Free the domain name.
  95. //
  96. NetApiBufferFree( NewDomainName );
  97. } else {
  98. NlPrint(( NL_CRITICAL,
  99. "ChangeLogWorker cannot get new domain name: %ld\n",
  100. NetStatus ));
  101. }
  102. LOCK_CHANGELOG();
  103. NlGlobalChangeLogNotifyBrowserIsRunning = FALSE;
  104. //
  105. // If there is nothing more to do,
  106. // exit the thread.
  107. //
  108. } else {
  109. NlPrint((NL_CHANGELOG, "ChangeLogWorker Thread is exiting \n"));
  110. NlGlobalChangeLogWorkerIsRunning = FALSE;
  111. break;
  112. }
  113. }
  114. UNLOCK_CHANGELOG();
  115. return;
  116. UNREFERENCED_PARAMETER( ChangeLogWorkerParam );
  117. }
  118. BOOL
  119. NlStartChangeLogWorkerThread(
  120. VOID
  121. )
  122. /*++
  123. Routine Description:
  124. Start the Change Log Worker thread if it is not already running.
  125. Enter with NlGlobalChangeLogCritSect locked.
  126. Arguments:
  127. None.
  128. Return Value:
  129. None.
  130. --*/
  131. {
  132. DWORD ThreadHandle;
  133. //
  134. // If the worker thread is already running, do nothing.
  135. //
  136. if ( IsChangeLogWorkerRunning() ) {
  137. return FALSE;
  138. }
  139. NlGlobalChangeLogWorkerThreadHandle = CreateThread(
  140. NULL, // No security attributes
  141. 0,
  142. (LPTHREAD_START_ROUTINE)
  143. NlChangeLogWorker,
  144. NULL,
  145. 0, // No special creation flags
  146. &ThreadHandle );
  147. if ( NlGlobalChangeLogWorkerThreadHandle == NULL ) {
  148. //
  149. // ?? Shouldn't we do something in non-debug case
  150. //
  151. NlPrint((NL_CRITICAL, "Can't create change log worker thread %lu\n",
  152. GetLastError() ));
  153. return FALSE;
  154. }
  155. NlGlobalChangeLogWorkerIsRunning = TRUE;
  156. return TRUE;
  157. }
  158. VOID
  159. NlStopChangeLogWorker(
  160. VOID
  161. )
  162. /*++
  163. Routine Description:
  164. Stops the worker thread if it is running and waits for it to stop.
  165. Arguments:
  166. NONE
  167. Return Value:
  168. NONE
  169. --*/
  170. {
  171. //
  172. // Determine if the worker thread is already running.
  173. //
  174. if ( NlGlobalChangeLogWorkerThreadHandle != NULL ) {
  175. //
  176. // We've asked the worker to stop. It should do so soon.
  177. // Wait for it to stop.
  178. //
  179. NlWaitForSingleObject( "Wait for worker to stop",
  180. NlGlobalChangeLogWorkerThreadHandle );
  181. CloseHandle( NlGlobalChangeLogWorkerThreadHandle );
  182. NlGlobalChangeLogWorkerThreadHandle = NULL;
  183. }
  184. return;
  185. }
  186. BOOL
  187. IsChangeLogWorkerRunning(
  188. VOID
  189. )
  190. /*++
  191. Routine Description:
  192. Test if the change log worker thread is running
  193. Enter with NlGlobalChangeLogCritSect locked.
  194. Arguments:
  195. NONE
  196. Return Value:
  197. TRUE - if the worker thread is running.
  198. FALSE - if the worker thread is not running.
  199. --*/
  200. {
  201. DWORD WaitStatus;
  202. //
  203. // Determine if the worker thread is already running.
  204. //
  205. if ( NlGlobalChangeLogWorkerThreadHandle != NULL ) {
  206. //
  207. // Time out immediately if the worker is still running.
  208. //
  209. WaitStatus = WaitForSingleObject(
  210. NlGlobalChangeLogWorkerThreadHandle, 0 );
  211. if ( WaitStatus == WAIT_TIMEOUT ) {
  212. //
  213. // Handle the case that the thread has finished
  214. // processing, but is in the process of exitting.
  215. //
  216. if ( !NlGlobalChangeLogWorkerIsRunning ) {
  217. NlStopChangeLogWorker();
  218. return FALSE;
  219. }
  220. return TRUE;
  221. } else if ( WaitStatus == 0 ) {
  222. CloseHandle( NlGlobalChangeLogWorkerThreadHandle );
  223. NlGlobalChangeLogWorkerThreadHandle = NULL;
  224. return FALSE;
  225. } else {
  226. NlPrint((NL_CRITICAL,
  227. "Cannot WaitFor Change Log Worker thread: %ld\n",
  228. WaitStatus ));
  229. return TRUE;
  230. }
  231. }
  232. return FALSE;
  233. }
  234. VOID
  235. NlWaitForChangeLogBrowserNotify(
  236. VOID
  237. )
  238. /*++
  239. Routine Description:
  240. Wait for up 20 seconds for the change log worker thread to finish
  241. the browser notification on the domain join.
  242. Arguments:
  243. None
  244. Return Value:
  245. None
  246. --*/
  247. {
  248. ULONG WaitCount = 0;
  249. //
  250. // Wait for 20 seconds max. This is a rare operation,
  251. // so just polling periodically is not too bad here.
  252. //
  253. LOCK_CHANGELOG();
  254. while ( WaitCount < 40 &&
  255. (NlGlobalChangeLogNotifyBrowser || NlGlobalChangeLogNotifyBrowserIsRunning) ) {
  256. if ( WaitCount == 0 ) {
  257. NlPrint(( NL_MISC,
  258. "NlWaitForChangeLogBrowserNotify: Waiting for change log worker to exit\n" ));
  259. }
  260. //
  261. // Sleep half a second
  262. //
  263. UNLOCK_CHANGELOG();
  264. Sleep( 500 );
  265. LOCK_CHANGELOG();
  266. WaitCount ++;
  267. }
  268. UNLOCK_CHANGELOG();
  269. if ( WaitCount == 40 ) {
  270. NlPrint(( NL_CRITICAL,
  271. "NlWaitForChangeLogBrowserNotify: Couldn't wait for change log worker exit\n" ));
  272. }
  273. }
  274. NTSTATUS
  275. NlSendChangeLogNotification(
  276. IN enum CHANGELOG_NOTIFICATION_TYPE EntryType,
  277. IN PUNICODE_STRING ObjectName,
  278. IN PSID ObjectSid,
  279. IN ULONG ObjectRid,
  280. IN GUID *ObjectGuid,
  281. IN GUID *DomainGuid,
  282. IN PUNICODE_STRING DomainName
  283. )
  284. /*++
  285. Routine Description:
  286. Put a ChangeLog Notification entry for netlogon to pick up.
  287. Arguments:
  288. EntryType - The type of the entry being inserted
  289. ObjectName - The name of the account being changed.
  290. ObjectSid - Sid of the account be changed.
  291. ObjectRid - Rid of the object being changed.
  292. ObjectGuid - Guid of the object being changed.
  293. DomainGuid - Guid of the domain the object is in
  294. DomainName - Name of the domain the object is in
  295. Return Value:
  296. Status of the operation.
  297. --*/
  298. {
  299. PCHANGELOG_NOTIFICATION Notification;
  300. LPBYTE Where;
  301. ULONG SidSize = 0;
  302. ULONG NameSize = 0;
  303. ULONG DomainNameSize = 0;
  304. ULONG Size;
  305. //
  306. // If the netlogon service isn't running (or at least starting),
  307. // don't queue messages to it.
  308. //
  309. if( NlGlobalChangeLogNetlogonState == NetlogonStopped ) {
  310. return STATUS_SUCCESS;
  311. }
  312. //
  313. // Allocate a buffer for the object name.
  314. //
  315. if ( ObjectSid != NULL ) {
  316. SidSize = RtlLengthSid( ObjectSid );
  317. }
  318. if ( ObjectName != NULL ) {
  319. NameSize = ObjectName->Length + sizeof(WCHAR);
  320. }
  321. if ( DomainName != NULL ) {
  322. DomainNameSize = DomainName->Length + sizeof(WCHAR);
  323. }
  324. Size = sizeof(*Notification) + SidSize + NameSize + DomainNameSize;
  325. Size = ROUND_UP_COUNT( Size, ALIGN_WORST );
  326. Notification = NetpMemoryAllocate( Size );
  327. if ( Notification == NULL ) {
  328. return STATUS_NO_MEMORY;
  329. }
  330. RtlZeroMemory( Notification, Size );
  331. Notification->EntryType = EntryType;
  332. Notification->ObjectRid = ObjectRid;
  333. Where = (LPBYTE) (Notification + 1);
  334. //
  335. // Copy the object sid into the buffer.
  336. //
  337. if ( ObjectSid != NULL ) {
  338. RtlCopyMemory( Where, ObjectSid, SidSize );
  339. Notification->ObjectSid = (PSID) Where;
  340. Where += SidSize;
  341. } else {
  342. Notification->ObjectSid = NULL;
  343. }
  344. //
  345. // Copy the object name into the buffer.
  346. //
  347. if ( ObjectName != NULL ) {
  348. Where = ROUND_UP_POINTER( Where, ALIGN_WCHAR );
  349. RtlCopyMemory( Where, ObjectName->Buffer, ObjectName->Length );
  350. ((LPWSTR)Where)[ObjectName->Length/sizeof(WCHAR)] = L'\0';
  351. RtlInitUnicodeString( &Notification->ObjectName, (LPWSTR)Where);
  352. Where += NameSize;
  353. } else {
  354. RtlInitUnicodeString( &Notification->ObjectName, NULL);
  355. }
  356. //
  357. // Copy the domain name into the buffer.
  358. //
  359. if ( DomainName != NULL ) {
  360. Where = ROUND_UP_POINTER( Where, ALIGN_WCHAR );
  361. RtlCopyMemory( Where, DomainName->Buffer, DomainName->Length );
  362. ((LPWSTR)Where)[DomainName->Length/sizeof(WCHAR)] = L'\0';
  363. RtlInitUnicodeString( &Notification->DomainName, (LPWSTR)Where);
  364. Where += DomainNameSize;
  365. } else {
  366. RtlInitUnicodeString( &Notification->DomainName, NULL);
  367. }
  368. //
  369. // Copy the GUIDs into the buffer
  370. //
  371. if ( ObjectGuid != NULL) {
  372. Notification->ObjectGuid = *ObjectGuid;
  373. }
  374. if ( DomainGuid != NULL) {
  375. Notification->DomainGuid = *DomainGuid;
  376. }
  377. //
  378. // Indicate we're about to send the event.
  379. //
  380. #if NETLOGONDBG
  381. EnterCriticalSection( &NlGlobalLogFileCritSect );
  382. NlPrint((NL_CHANGELOG,
  383. "NlSendChangeLogNotification: sent %ld for",
  384. Notification->EntryType ));
  385. if ( ObjectName != NULL ) {
  386. NlPrint((NL_CHANGELOG,
  387. " %wZ",
  388. ObjectName));
  389. }
  390. if ( DomainName != NULL ) {
  391. NlPrint((NL_CHANGELOG,
  392. " Dom:%wZ",
  393. DomainName));
  394. }
  395. if ( ObjectRid != 0 ) {
  396. NlPrint((NL_CHANGELOG,
  397. " Rid:0x%lx",
  398. ObjectRid ));
  399. }
  400. if ( ObjectSid != NULL ) {
  401. NlPrint((NL_CHANGELOG, " Sid:" ));
  402. NlpDumpSid( NL_CHANGELOG, ObjectSid );
  403. }
  404. if ( ObjectGuid != NULL ) {
  405. NlPrint((NL_CHANGELOG, " Obj Guid:" ));
  406. NlpDumpGuid( NL_CHANGELOG, ObjectGuid );
  407. }
  408. if ( DomainGuid != NULL ) {
  409. NlPrint((NL_CHANGELOG, " Dom Guid:" ));
  410. NlpDumpGuid( NL_CHANGELOG, DomainGuid );
  411. }
  412. NlPrint((NL_CHANGELOG, "\n" ));
  413. LeaveCriticalSection( &NlGlobalLogFileCritSect );
  414. #endif // NETLOGONDBG
  415. //
  416. // Insert the entry into the list
  417. //
  418. LOCK_CHANGELOG();
  419. InsertTailList( &NlGlobalChangeLogNotifications, &Notification->Next );
  420. UNLOCK_CHANGELOG();
  421. if ( !SetEvent( NlGlobalChangeLogEvent ) ) {
  422. NlPrint((NL_CRITICAL,
  423. "Cannot set ChangeLog event: %lu\n",
  424. GetLastError() ));
  425. }
  426. return STATUS_SUCCESS;
  427. }
  428. NTSTATUS
  429. I_NetNotifyDelta (
  430. IN SECURITY_DB_TYPE DbType,
  431. IN LARGE_INTEGER SerialNumber,
  432. IN SECURITY_DB_DELTA_TYPE DeltaType,
  433. IN SECURITY_DB_OBJECT_TYPE ObjectType,
  434. IN ULONG ObjectRid,
  435. IN PSID ObjectSid,
  436. IN PUNICODE_STRING ObjectName,
  437. IN DWORD ReplicateImmediately,
  438. IN PSAM_DELTA_DATA MemberId
  439. )
  440. /*++
  441. Routine Description:
  442. This function is called by the SAM and LSA services after each
  443. change is made to the SAM and LSA databases. The services describe
  444. the type of object that is modified, the type of modification made
  445. on the object, the serial number of this modification etc. This
  446. information is stored for later retrieval when a BDC or member
  447. server wants a copy of this change. See the description of
  448. I_NetSamDeltas for a description of how the change log is used.
  449. Add a change log entry to circular change log maintained in cache as
  450. well as on the disk and update the head and tail pointers
  451. It is assumed that Tail points to a block where this new change log
  452. entry may be stored.
  453. Arguments:
  454. DbType - Type of the database that has been modified.
  455. SerialNumber - The value of the DomainModifiedCount field for the
  456. domain following the modification.
  457. DeltaType - The type of modification that has been made on the object.
  458. ObjectType - The type of object that has been modified.
  459. ObjectRid - The relative ID of the object that has been modified.
  460. This parameter is valid only when the object type specified is
  461. either SecurityDbObjectSamUser, SecurityDbObjectSamGroup or
  462. SecurityDbObjectSamAlias otherwise this parameter is set to zero.
  463. ObjectSid - The SID of the object that has been modified. If the object
  464. modified is in a SAM database, ObjectSid is the DomainId of the Domain
  465. containing the object.
  466. ObjectName - The name of the secret object when the object type
  467. specified is SecurityDbObjectLsaSecret or the old name of the object
  468. when the object type specified is either SecurityDbObjectSamUser,
  469. SecurityDbObjectSamGroup or SecurityDbObjectSamAlias and the delta
  470. type is SecurityDbRename otherwise this parameter is set to NULL.
  471. ReplicateImmediately - TRUE if the change should be immediately
  472. replicated to all BDCs. A password change should set the flag
  473. TRUE.
  474. MemberId - This parameter is specified when group/alias membership
  475. is modified. This structure will then point to the member's ID that
  476. has been updated.
  477. Return Value:
  478. STATUS_SUCCESS - The Service completed successfully.
  479. --*/
  480. {
  481. NTSTATUS Status;
  482. CHANGELOG_ENTRY ChangeLogEntry;
  483. NETLOGON_DELTA_TYPE NetlogonDeltaType;
  484. USHORT Flags = 0;
  485. //
  486. // Ensure the role is right. Otherwise, all the globals used below
  487. // aren't initialized.
  488. //
  489. if ( NlGlobalChangeLogRole != ChangeLogPrimary &&
  490. NlGlobalChangeLogRole != ChangeLogBackup ) {
  491. return STATUS_INVALID_DOMAIN_ROLE;
  492. }
  493. //
  494. // Also make sure that the change log cache is available.
  495. //
  496. if ( NlGlobalChangeLogDesc.Buffer == NULL ) {
  497. return STATUS_INVALID_DOMAIN_ROLE;
  498. }
  499. //
  500. // Determine the database index.
  501. //
  502. if( DbType == SecurityDbLsa ) {
  503. ChangeLogEntry.DBIndex = LSA_DB;
  504. } else if( DbType == SecurityDbSam ) {
  505. if ( RtlEqualSid( ObjectSid, NlGlobalChangeLogBuiltinDomainSid )) {
  506. ChangeLogEntry.DBIndex = BUILTIN_DB;
  507. } else {
  508. ChangeLogEntry.DBIndex = SAM_DB;
  509. }
  510. //
  511. // For the SAM database, we no longer need the ObjectSid.
  512. // Null out the pointer to prevent us from storing it in the
  513. // changelog.
  514. //
  515. ObjectSid = NULL;
  516. } else {
  517. //
  518. // unknown database, do nothing.
  519. //
  520. NlPrint((NL_CRITICAL,
  521. "I_NetNotifyDelta: Unknown database: %ld\n",
  522. DbType ));
  523. return STATUS_SUCCESS;
  524. }
  525. //
  526. // Map object type and delta type to NetlogonDeltaType
  527. //
  528. switch( ObjectType ) {
  529. case SecurityDbObjectLsaPolicy:
  530. switch (DeltaType) {
  531. case SecurityDbNew:
  532. case SecurityDbChange:
  533. NetlogonDeltaType = AddOrChangeLsaPolicy;
  534. break;
  535. // unknown delta type
  536. default:
  537. NlPrint((NL_CRITICAL,
  538. "I_NetNotifyDelta: Unknown deltatype for policy: %ld\n",
  539. DeltaType ));
  540. return STATUS_SUCCESS;
  541. }
  542. break;
  543. case SecurityDbObjectLsaTDomain:
  544. switch (DeltaType) {
  545. case SecurityDbNew:
  546. case SecurityDbChange:
  547. NetlogonDeltaType = AddOrChangeLsaTDomain;
  548. break;
  549. case SecurityDbDelete:
  550. NetlogonDeltaType = DeleteLsaTDomain;
  551. break;
  552. // unknown delta type
  553. default:
  554. NlPrint((NL_CRITICAL,
  555. "I_NetNotifyDelta: Unknown deltatype for tdomain: %ld\n",
  556. DeltaType ));
  557. return STATUS_SUCCESS;
  558. }
  559. break;
  560. case SecurityDbObjectLsaAccount:
  561. switch (DeltaType) {
  562. case SecurityDbNew:
  563. case SecurityDbChange:
  564. NetlogonDeltaType = AddOrChangeLsaAccount;
  565. break;
  566. case SecurityDbDelete:
  567. NetlogonDeltaType = DeleteLsaAccount;
  568. break;
  569. // unknown delta type
  570. default:
  571. NlPrint((NL_CRITICAL,
  572. "I_NetNotifyDelta: Unknown deltatype for lsa account: %ld\n",
  573. DeltaType ));
  574. return STATUS_SUCCESS;
  575. }
  576. break;
  577. case SecurityDbObjectLsaSecret:
  578. switch (DeltaType) {
  579. case SecurityDbNew:
  580. case SecurityDbChange:
  581. NetlogonDeltaType = AddOrChangeLsaSecret;
  582. break;
  583. case SecurityDbDelete:
  584. NetlogonDeltaType = DeleteLsaSecret;
  585. break;
  586. // unknown delta type
  587. default:
  588. NlPrint((NL_CRITICAL,
  589. "I_NetNotifyDelta: Unknown deltatype for lsa secret: %ld\n",
  590. DeltaType ));
  591. return STATUS_SUCCESS;
  592. }
  593. break;
  594. case SecurityDbObjectSamDomain:
  595. switch (DeltaType) {
  596. case SecurityDbNew:
  597. case SecurityDbChange:
  598. NetlogonDeltaType = AddOrChangeDomain;
  599. break;
  600. // unknown delta type
  601. default:
  602. NlPrint((NL_CRITICAL,
  603. "I_NetNotifyDelta: Unknown deltatype for sam domain: %ld\n",
  604. DeltaType ));
  605. return STATUS_SUCCESS;
  606. }
  607. break;
  608. case SecurityDbObjectSamUser:
  609. switch (DeltaType) {
  610. case SecurityDbChangePassword:
  611. case SecurityDbNew:
  612. case SecurityDbChange:
  613. case SecurityDbRename:
  614. NetlogonDeltaType = AddOrChangeUser;
  615. break;
  616. case SecurityDbDelete:
  617. NetlogonDeltaType = DeleteUser;
  618. break;
  619. //
  620. // unknown delta type
  621. //
  622. default:
  623. NlPrint((NL_CRITICAL,
  624. "I_NetNotifyDelta: Unknown deltatype for sam user: %ld\n",
  625. DeltaType ));
  626. return STATUS_SUCCESS;
  627. }
  628. break;
  629. case SecurityDbObjectSamGroup:
  630. switch ( DeltaType ) {
  631. case SecurityDbNew:
  632. case SecurityDbChange:
  633. case SecurityDbRename:
  634. case SecurityDbChangeMemberAdd:
  635. case SecurityDbChangeMemberSet:
  636. case SecurityDbChangeMemberDel:
  637. NetlogonDeltaType = AddOrChangeGroup;
  638. break;
  639. case SecurityDbDelete:
  640. NetlogonDeltaType = DeleteGroup;
  641. break;
  642. //
  643. // unknown delta type
  644. //
  645. default:
  646. NlPrint((NL_CRITICAL,
  647. "I_NetNotifyDelta: Unknown deltatype for sam group: %ld\n",
  648. DeltaType ));
  649. return STATUS_SUCCESS;
  650. }
  651. break;
  652. case SecurityDbObjectSamAlias:
  653. switch (DeltaType) {
  654. case SecurityDbNew:
  655. case SecurityDbChange:
  656. case SecurityDbRename:
  657. case SecurityDbChangeMemberAdd:
  658. case SecurityDbChangeMemberSet:
  659. case SecurityDbChangeMemberDel:
  660. NetlogonDeltaType = AddOrChangeAlias;
  661. break;
  662. case SecurityDbDelete:
  663. NetlogonDeltaType = DeleteAlias;
  664. break;
  665. // unknown delta type
  666. default:
  667. NlPrint((NL_CRITICAL,
  668. "I_NetNotifyDelta: Unknown deltatype for sam alias: %ld\n",
  669. DeltaType ));
  670. return STATUS_SUCCESS;
  671. }
  672. break;
  673. default:
  674. // unknown object type
  675. NlPrint((NL_CRITICAL,
  676. "I_NetNotifyDelta: Unknown object type: %ld\n",
  677. ObjectType ));
  678. return STATUS_SUCCESS;
  679. }
  680. //
  681. // Build the changelog entry and write it to the changelog
  682. //
  683. ChangeLogEntry.DeltaType = (UCHAR)NetlogonDeltaType;
  684. ChangeLogEntry.SerialNumber = SerialNumber;
  685. ChangeLogEntry.ObjectRid = ObjectRid;
  686. ChangeLogEntry.Flags = Flags;
  687. Status = NlWriteChangeLogEntry( &NlGlobalChangeLogDesc,
  688. &ChangeLogEntry,
  689. ObjectSid,
  690. ObjectName,
  691. TRUE );
  692. if ( !NT_SUCCESS(Status) ) {
  693. return Status;
  694. }
  695. //
  696. // If this change requires immediate replication, do so
  697. //
  698. if( ReplicateImmediately ) {
  699. LOCK_CHANGELOG();
  700. NlGlobalChangeLogReplicateImmediately = TRUE;
  701. UNLOCK_CHANGELOG();
  702. if ( !SetEvent( NlGlobalChangeLogEvent ) ) {
  703. NlPrint((NL_CRITICAL,
  704. "Cannot set ChangeLog event: %lu\n",
  705. GetLastError() ));
  706. }
  707. }
  708. return STATUS_SUCCESS;
  709. UNREFERENCED_PARAMETER( MemberId );
  710. }
  711. NTSTATUS
  712. I_NetLogonGetSerialNumber (
  713. IN SECURITY_DB_TYPE DbType,
  714. IN PSID DomainSid,
  715. OUT PLARGE_INTEGER SerialNumber
  716. )
  717. /*++
  718. Routine Description:
  719. This function is called by the SAM and LSA services when they startup
  720. to get the current serial number written to the changelog.
  721. Arguments:
  722. DbType - Type of the database that has been modified.
  723. DomainSid - For the SAM and builtin database, this specifies the DomainId of
  724. the domain whose serial number is to be returned.
  725. SerialNumber - Returns the latest set value of the DomainModifiedCount
  726. field for the domain.
  727. Return Value:
  728. STATUS_SUCCESS - The Service completed successfully.
  729. STATUS_INVALID_DOMAIN_ROLE - This machine is not the PDC.
  730. --*/
  731. {
  732. NTSTATUS Status;
  733. CHANGELOG_ENTRY ChangeLogEntry;
  734. NETLOGON_DELTA_TYPE NetlogonDeltaType;
  735. USHORT Flags = 0;
  736. ULONG DbIndex;
  737. //
  738. // Ensure the role is right. Otherwise, all the globals used below
  739. // aren't initialized.
  740. //
  741. if ( NlGlobalChangeLogRole != ChangeLogPrimary &&
  742. NlGlobalChangeLogRole != ChangeLogBackup ) {
  743. NlPrint((NL_CHANGELOG,
  744. "I_NetLogonGetSerialNumber: failed 1\n" ));
  745. return STATUS_INVALID_DOMAIN_ROLE;
  746. }
  747. //
  748. // Also make sure that the change log cache is available.
  749. //
  750. if ( NlGlobalChangeLogDesc.Buffer == NULL ) {
  751. NlPrint((NL_CHANGELOG,
  752. "I_NetLogonGetSerialNumber: failed 2\n" ));
  753. return STATUS_INVALID_DOMAIN_ROLE;
  754. }
  755. //
  756. // Determine the database index.
  757. //
  758. if( DbType == SecurityDbLsa ) {
  759. DbIndex = LSA_DB;
  760. } else if( DbType == SecurityDbSam ) {
  761. if ( RtlEqualSid( DomainSid, NlGlobalChangeLogBuiltinDomainSid )) {
  762. DbIndex = BUILTIN_DB;
  763. } else {
  764. DbIndex = SAM_DB;
  765. }
  766. } else {
  767. NlPrint((NL_CHANGELOG,
  768. "I_NetLogonGetSerialNumber: failed 3\n" ));
  769. return STATUS_INVALID_DOMAIN_ROLE;
  770. }
  771. //
  772. // Return the current serial number.
  773. //
  774. SerialNumber->QuadPart = NlGlobalChangeLogDesc.SerialNumber[DbIndex].QuadPart;
  775. NlPrint((NL_CHANGELOG,
  776. "I_NetLogonGetSerialNumber: returns 0x%lx 0x%lx\n",
  777. SerialNumber->HighPart,
  778. SerialNumber->LowPart ));
  779. return STATUS_SUCCESS;
  780. }
  781. NTSTATUS
  782. NlInitChangeLogBuffer(
  783. VOID
  784. )
  785. /*++
  786. Routine Description:
  787. Open the change log file (netlogon.chg) for reading or writing one or
  788. more records. Create this file if it does not exist or is out of
  789. sync with the SAM database (see note below).
  790. This file must be opened for R/W (deny-none share mode) at the time
  791. the cache is initialized. If the file already exists when NETLOGON
  792. service started, its contents will be cached in its entirety
  793. provided the last change log record bears the same serial number as
  794. the serial number field in SAM database else this file will be
  795. removed and a new one created. If the change log file did not exist
  796. then it will be created.
  797. Arguments:
  798. NONE
  799. Return Value:
  800. NT Status code
  801. --*/
  802. {
  803. NTSTATUS Status;
  804. NET_API_STATUS NetStatus;
  805. UINT WindowsDirectoryLength;
  806. WCHAR ChangeLogFile[MAX_PATH+1];
  807. LPNET_CONFIG_HANDLE SectionHandle = NULL;
  808. DWORD NewChangeLogSize;
  809. //
  810. // Initialize
  811. //
  812. LOCK_CHANGELOG();
  813. //
  814. // Get the size of the changelog.
  815. //
  816. // Open the NetLogon configuration section.
  817. //
  818. NewChangeLogSize = DEFAULT_CHANGELOGSIZE;
  819. NetStatus = NetpOpenConfigData(
  820. &SectionHandle,
  821. NULL, // no server name.
  822. SERVICE_NETLOGON,
  823. TRUE ); // we only want readonly access
  824. if ( NetStatus == NO_ERROR ) {
  825. (VOID) NlParseOne( SectionHandle,
  826. FALSE, // not a GP section
  827. NETLOGON_KEYWORD_CHANGELOGSIZE,
  828. DEFAULT_CHANGELOGSIZE,
  829. MIN_CHANGELOGSIZE,
  830. MAX_CHANGELOGSIZE,
  831. &NewChangeLogSize );
  832. (VOID) NetpCloseConfigData( SectionHandle );
  833. }
  834. NewChangeLogSize = ROUND_UP_COUNT( NewChangeLogSize, ALIGN_WORST);
  835. #ifdef notdef
  836. NlPrint((NL_INIT, "ChangeLogSize: 0x%lx\n", NewChangeLogSize ));
  837. #endif // notdef
  838. //
  839. // Build the change log file name
  840. //
  841. WindowsDirectoryLength = GetSystemWindowsDirectoryW(
  842. NlGlobalChangeLogFilePrefix,
  843. sizeof(NlGlobalChangeLogFilePrefix)/sizeof(WCHAR) );
  844. if ( WindowsDirectoryLength == 0 ) {
  845. NlPrint((NL_CRITICAL,"Unable to get changelog file directory name, "
  846. "WinError = %ld \n", GetLastError() ));
  847. NlGlobalChangeLogFilePrefix[0] = L'\0';
  848. goto CleanChangeLogFile;
  849. }
  850. if ( WindowsDirectoryLength * sizeof(WCHAR) + sizeof(CHANGELOG_FILE_PREFIX) +
  851. CHANGELOG_FILE_POSTFIX_LENGTH * sizeof(WCHAR)
  852. > sizeof(NlGlobalChangeLogFilePrefix) ) {
  853. NlPrint((NL_CRITICAL,"Changelog file directory name length is "
  854. "too long \n" ));
  855. NlGlobalChangeLogFilePrefix[0] = L'\0';
  856. goto CleanChangeLogFile;
  857. }
  858. wcscat( NlGlobalChangeLogFilePrefix, CHANGELOG_FILE_PREFIX );
  859. //
  860. // Read in the existing changelog file.
  861. //
  862. wcscpy( ChangeLogFile, NlGlobalChangeLogFilePrefix );
  863. wcscat( ChangeLogFile, CHANGELOG_FILE_POSTFIX );
  864. InitChangeLogDesc( &NlGlobalChangeLogDesc );
  865. Status = NlOpenChangeLogFile( ChangeLogFile, &NlGlobalChangeLogDesc, FALSE );
  866. if ( !NT_SUCCESS(Status) ) {
  867. goto CleanChangeLogFile;
  868. }
  869. //
  870. // Convert the changelog file to the right size/version.
  871. //
  872. Status = NlResizeChangeLogFile( &NlGlobalChangeLogDesc, NewChangeLogSize );
  873. if ( !NT_SUCCESS(Status) ) {
  874. goto CleanChangeLogFile;
  875. }
  876. goto Cleanup;
  877. //
  878. // CleanChangeLogFile
  879. //
  880. CleanChangeLogFile:
  881. //
  882. // If we just need to start with a newly initialized file,
  883. // do it.
  884. //
  885. Status = NlResetChangeLog( &NlGlobalChangeLogDesc, NewChangeLogSize );
  886. Cleanup:
  887. //
  888. // Free any resources on error.
  889. //
  890. if ( !NT_SUCCESS(Status) ) {
  891. NlCloseChangeLogFile( &NlGlobalChangeLogDesc );
  892. }
  893. UNLOCK_CHANGELOG();
  894. return Status;
  895. }
  896. NTSTATUS
  897. I_NetNotifyRole (
  898. IN POLICY_LSA_SERVER_ROLE Role
  899. )
  900. /*++
  901. Routine Description:
  902. This function is called by the LSA service upon LSA initialization
  903. and when LSA changes domain role. This routine will initialize the
  904. change log cache if the role specified is PDC or delete the change
  905. log cache if the role specified is other than PDC.
  906. When this function initializing the change log if the change log
  907. currently exists on disk, the cache will be initialized from disk.
  908. LSA should treat errors from this routine as non-fatal. LSA should
  909. log the errors so they may be corrected then continue
  910. initialization. However, LSA should treat the system databases as
  911. read-only in this case.
  912. Arguments:
  913. Role - Current role of the server.
  914. Return Value:
  915. STATUS_SUCCESS - The Service completed successfully.
  916. --*/
  917. {
  918. NTSTATUS Status = STATUS_SUCCESS;
  919. CHANGELOG_ROLE PreviousChangeLogRole;
  920. //
  921. // Change the role of the changelog itself.
  922. //
  923. Status = NetpNotifyRole ( Role );
  924. //
  925. // Tell the netlogon service about the role change.
  926. //
  927. if ( NT_SUCCESS(Status) ) {
  928. Status = NlSendChangeLogNotification( ChangeLogRoleChanged,
  929. NULL,
  930. NULL,
  931. 0,
  932. NULL, // Object GUID,
  933. NULL, // Domain GUID,
  934. NULL ); // Domain Name
  935. }
  936. return Status;
  937. }
  938. NTSTATUS
  939. NetpNotifyRole (
  940. IN POLICY_LSA_SERVER_ROLE Role
  941. )
  942. /*++
  943. Routine Description:
  944. This function is called by the LSA service upon LSA initialization
  945. and when LSA changes domain role. This routine will initialize the
  946. change log cache if the role specified is PDC or delete the change
  947. log cache if the role specified is other than PDC.
  948. When this function initializing the change log if the change log
  949. currently exists on disk, the cache will be initialized from disk.
  950. LSA should treat errors from this routine as non-fatal. LSA should
  951. log the errors so they may be corrected then continue
  952. initialization. However, LSA should treat the system databases as
  953. read-only in this case.
  954. Arguments:
  955. Role - Current role of the server.
  956. Return Value:
  957. STATUS_SUCCESS - The Service completed successfully.
  958. --*/
  959. {
  960. NTSTATUS Status = STATUS_SUCCESS;
  961. CHANGELOG_ROLE PreviousChangeLogRole;
  962. //
  963. // If this is a workstation, simply return.
  964. //
  965. if ( NlGlobalChangeLogRole == ChangeLogMemberWorkstation ) {
  966. return STATUS_SUCCESS;
  967. }
  968. //
  969. // Set our role to the new value.
  970. //
  971. LOCK_CHANGELOG();
  972. PreviousChangeLogRole = NlGlobalChangeLogRole;
  973. if( Role == PolicyServerRolePrimary) {
  974. NlGlobalChangeLogRole = ChangeLogPrimary;
  975. NlPrint(( NL_DOMAIN,
  976. "NetpNotifyRole: LSA setting our role to Primary.\n"));
  977. } else {
  978. NlGlobalChangeLogRole = ChangeLogBackup;
  979. NlPrint(( NL_DOMAIN,
  980. "NetpNotifyRole: LSA setting our role to Backup.\n"));
  981. }
  982. //
  983. // If the role has changed,
  984. // Delete any previous change log buffer.
  985. // (Reopen it now to resize it upon role change.)
  986. //
  987. if ( NlGlobalChangeLogRole != PreviousChangeLogRole ) {
  988. NlCloseChangeLogFile( &NlGlobalChangeLogDesc );
  989. Status = NlInitChangeLogBuffer();
  990. }
  991. UNLOCK_CHANGELOG();
  992. return Status;
  993. }
  994. //
  995. // Defines a set of handles to Netlogon.dll
  996. //
  997. #if NETLOGONDBG
  998. #define MAX_NETLOGON_DLL_HANDLES 8
  999. PHANDLE NlGlobalNetlogonDllHandles[MAX_NETLOGON_DLL_HANDLES];
  1000. ULONG NlGlobalNetlogonDllHandleCount = 0;
  1001. #endif // NETLOGONDBG
  1002. NTSTATUS
  1003. I_NetNotifyNetlogonDllHandle (
  1004. IN PHANDLE NetlogonDllHandle
  1005. )
  1006. /*++
  1007. Routine Description:
  1008. Registers the fact that a service has an open handle to the NetlogonDll.
  1009. This function is called by the LSA service, SAM service, and MSV1_0
  1010. authentication package when the load netlogon.dll into the lsass.exe
  1011. process. Netlogon will close these handles (and NULL the handle) when
  1012. it wants to unload the DLL from the lsass.exe process. The DLL is only
  1013. unloaded for debugging purposes.
  1014. Arguments:
  1015. NetlogonDllHandle - Specifies a pointer to a handle to netlogon.dll
  1016. Return Value:
  1017. STATUS_SUCCESS - The Service completed successfully.
  1018. --*/
  1019. {
  1020. #if NETLOGONDBG
  1021. LOCK_CHANGELOG();
  1022. if ( NlGlobalNetlogonDllHandleCount >= MAX_NETLOGON_DLL_HANDLES ) {
  1023. NlPrint((NL_CRITICAL, "Too many Netlogon Dll handles registered.\n" ));
  1024. } else {
  1025. #ifdef notdef
  1026. NlPrint(( NL_MISC,
  1027. "I_NetNotifyNetlogonDllHandle loading 0x%lx %lx (%ld)\n",
  1028. NetlogonDllHandle,
  1029. *NetlogonDllHandle,
  1030. NlGlobalNetlogonDllHandleCount ));
  1031. #endif // notdef
  1032. NlGlobalNetlogonDllHandles[NlGlobalNetlogonDllHandleCount] =
  1033. NetlogonDllHandle;
  1034. NlGlobalNetlogonDllHandleCount++;
  1035. }
  1036. UNLOCK_CHANGELOG();
  1037. #endif // NETLOGONDBG
  1038. return STATUS_SUCCESS;
  1039. }
  1040. NET_API_STATUS
  1041. NlpFreeNetlogonDllHandles (
  1042. VOID
  1043. )
  1044. /*++
  1045. Routine Description:
  1046. Free any curretly register NetlogonDll handles.
  1047. Arguments:
  1048. None.
  1049. Return Value:
  1050. None.
  1051. --*/
  1052. {
  1053. NET_API_STATUS NetStatus = NO_ERROR;
  1054. #if NETLOGONDBG
  1055. ULONG i;
  1056. ULONG NewHandleCount = 0;
  1057. LOCK_CHANGELOG();
  1058. for ( i=0; i<NlGlobalNetlogonDllHandleCount; i++ ) {
  1059. if ( !FreeLibrary( *(NlGlobalNetlogonDllHandles[i]) ) ) {
  1060. NetStatus = GetLastError();
  1061. NlPrint(( NL_CRITICAL,
  1062. "Cannot Free NetlogonDll handle. %ld\n",
  1063. NetStatus ));
  1064. NlGlobalNetlogonDllHandles[NewHandleCount] =
  1065. NlGlobalNetlogonDllHandles[i];
  1066. NewHandleCount++;
  1067. } else {
  1068. NlPrint(( NL_MISC,
  1069. "NlpFreeNetlogonDllHandle freed 0x%lx 0x%lx (%ld)\n",
  1070. NlGlobalNetlogonDllHandles[i],
  1071. *(NlGlobalNetlogonDllHandles[i]),
  1072. i ));
  1073. *(NlGlobalNetlogonDllHandles[i]) = NULL;
  1074. }
  1075. }
  1076. NlGlobalNetlogonDllHandleCount = NewHandleCount;
  1077. UNLOCK_CHANGELOG();
  1078. #endif // NETLOGONDBG
  1079. return NetStatus;
  1080. }
  1081. NTSTATUS
  1082. I_NetNotifyMachineAccount (
  1083. IN ULONG ObjectRid,
  1084. IN PSID DomainSid,
  1085. IN ULONG OldUserAccountControl,
  1086. IN ULONG NewUserAccountControl,
  1087. IN PUNICODE_STRING ObjectName
  1088. )
  1089. /*++
  1090. Routine Description:
  1091. This function is called by the SAM to indicate that the account type
  1092. of a machine account has changed. Specifically, if
  1093. USER_INTERDOMAIN_TRUST_ACCOUNT, USER_WORKSTATION_TRUST_ACCOUNT, or
  1094. USER_SERVER_TRUST_ACCOUNT change for a particular account, this
  1095. routine is called to let Netlogon know of the account change.
  1096. This function is called for both PDC and BDC.
  1097. Arguments:
  1098. ObjectRid - The relative ID of the object that has been modified.
  1099. DomainSid - Specifies the SID of the Domain containing the object.
  1100. OldUserAccountControl - Specifies the previous value of the
  1101. UserAccountControl field of the user.
  1102. NewUserAccountControl - Specifies the new (current) value of the
  1103. UserAccountControl field of the user.
  1104. ObjectName - The name of the account being changed.
  1105. Return Value:
  1106. Status of the operation.
  1107. --*/
  1108. {
  1109. NTSTATUS Status;
  1110. NTSTATUS SavedStatus = STATUS_SUCCESS;
  1111. //
  1112. // If the netlogon service isn't running,
  1113. // Don't bother with the coming and going of accounts.
  1114. //
  1115. if( NlGlobalChangeLogNetlogonState == NetlogonStopped ) {
  1116. return(STATUS_SUCCESS);
  1117. }
  1118. //
  1119. // If this is windows NT,
  1120. // There is nothing to maintain.
  1121. //
  1122. if ( NlGlobalChangeLogRole == ChangeLogMemberWorkstation ) {
  1123. return(STATUS_SUCCESS);
  1124. }
  1125. //
  1126. // Make available just the machine account bits.
  1127. //
  1128. OldUserAccountControl &= USER_MACHINE_ACCOUNT_MASK;
  1129. NewUserAccountControl &= USER_MACHINE_ACCOUNT_MASK;
  1130. if ( OldUserAccountControl == NewUserAccountControl ) {
  1131. return STATUS_SUCCESS;
  1132. }
  1133. //
  1134. // Handle deletion of a Workstation Trust Account
  1135. // Handle deletion of a Server Trust Account
  1136. //
  1137. if ( OldUserAccountControl == USER_SERVER_TRUST_ACCOUNT ||
  1138. OldUserAccountControl == USER_WORKSTATION_TRUST_ACCOUNT ) {
  1139. Status = NlSendChangeLogNotification( ChangeLogTrustAccountDeleted,
  1140. ObjectName,
  1141. NULL,
  1142. 0,
  1143. NULL, // Object GUID,
  1144. NULL, // Domain GUID,
  1145. NULL ); // Domain Name
  1146. if ( NT_SUCCESS(SavedStatus) ) {
  1147. SavedStatus = Status;
  1148. }
  1149. }
  1150. //
  1151. // Handle creation or change of a Workstation Trust Account
  1152. // Handle creation or change of a Server Trust Account
  1153. //
  1154. // Sam is no longer capable of telling me the "previous" value of
  1155. // account control.
  1156. //
  1157. if ( NewUserAccountControl == USER_SERVER_TRUST_ACCOUNT ||
  1158. NewUserAccountControl == USER_WORKSTATION_TRUST_ACCOUNT ) {
  1159. NETLOGON_SECURE_CHANNEL_TYPE SecureChannelType;
  1160. GUID ObjectGuid;
  1161. if ( NewUserAccountControl == USER_SERVER_TRUST_ACCOUNT ) {
  1162. SecureChannelType = ServerSecureChannel;
  1163. } else if ( NewUserAccountControl == USER_WORKSTATION_TRUST_ACCOUNT ) {
  1164. SecureChannelType = WorkstationSecureChannel;
  1165. }
  1166. RtlZeroMemory( &ObjectGuid, sizeof(ObjectGuid) );
  1167. *(PULONG)&ObjectGuid = SecureChannelType;
  1168. Status = NlSendChangeLogNotification( ChangeLogTrustAccountAdded,
  1169. ObjectName,
  1170. NULL,
  1171. ObjectRid,
  1172. &ObjectGuid, // Object GUID
  1173. NULL, // Domain GUID
  1174. NULL ); // Domain Name
  1175. if ( NT_SUCCESS(SavedStatus) ) {
  1176. SavedStatus = Status;
  1177. }
  1178. }
  1179. return SavedStatus;
  1180. UNREFERENCED_PARAMETER( DomainSid );
  1181. }
  1182. NTSTATUS
  1183. I_NetNotifyDsChange(
  1184. IN NL_DS_CHANGE_TYPE DsChangeType
  1185. )
  1186. /*++
  1187. Routine Description:
  1188. This function is called by the LSA to indicate that configuration information
  1189. in the DS has changed.
  1190. This function is called for both PDC and BDC.
  1191. Arguments:
  1192. DsChangeType - Indicates the type of information that has changed.
  1193. Return Value:
  1194. Status of the operation.
  1195. --*/
  1196. {
  1197. NTSTATUS Status;
  1198. //
  1199. // If the netlogon service isn't running,
  1200. // Don't bother with the coming and going of DS information.
  1201. //
  1202. if( NlGlobalChangeLogNetlogonState == NetlogonStopped ) {
  1203. return(STATUS_SUCCESS);
  1204. }
  1205. //
  1206. // If this is windows NT,
  1207. // There is nothing to maintain.
  1208. //
  1209. if ( NlGlobalChangeLogRole == ChangeLogMemberWorkstation ) {
  1210. return(STATUS_SUCCESS);
  1211. }
  1212. //
  1213. // If this is a notification about the DC demotion,
  1214. // just set the global boolean accordingly.
  1215. //
  1216. if ( DsChangeType == NlDcDemotionInProgress ) {
  1217. NlGlobalDcDemotionInProgress = TRUE;
  1218. return(STATUS_SUCCESS);
  1219. }
  1220. if ( DsChangeType == NlDcDemotionCompleted ) {
  1221. NlGlobalDcDemotionInProgress = FALSE;
  1222. return(STATUS_SUCCESS);
  1223. }
  1224. //
  1225. // Reset the TrustInfoUpToDate event so that any thread that wants to
  1226. // access the trust info list will wait until the info is updated (by
  1227. // the NlInitTrustList function).
  1228. //
  1229. if ( DsChangeType == NlOrgChanged ) {
  1230. if ( !ResetEvent( NlGlobalTrustInfoUpToDateEvent ) ) {
  1231. NlPrint((NL_CRITICAL,
  1232. "Cannot reset NlGlobalTrustInfoUpToDateEvent event: %lu\n",
  1233. GetLastError() ));
  1234. }
  1235. }
  1236. //
  1237. // Tell the netlogon service about the change.
  1238. //
  1239. Status = NlSendChangeLogNotification( ChangeLogDsChanged,
  1240. NULL,
  1241. NULL,
  1242. (ULONG) DsChangeType,
  1243. NULL, // Object GUID,
  1244. NULL, // Domain GUID,
  1245. NULL ); // Domain Name
  1246. return Status;
  1247. }
  1248. VOID
  1249. I_NetNotifyLsaPolicyChange(
  1250. IN POLICY_NOTIFICATION_INFORMATION_CLASS ChangeInfoClass
  1251. )
  1252. /*++
  1253. Routine Description:
  1254. This function is called by the LSA to indicate that policy information
  1255. in the LSA has changed.
  1256. This function is called for both PDC and BDC.
  1257. Arguments:
  1258. DsChangeType - Indicates the type of information that has changed.
  1259. Return Value:
  1260. Status of the operation.
  1261. --*/
  1262. {
  1263. NTSTATUS Status;
  1264. //
  1265. // If the netlogon service is running,
  1266. // Tell it about the change.
  1267. //
  1268. // It will, in turn, tell the bowser.
  1269. //
  1270. if( NlGlobalChangeLogNetlogonState != NetlogonStopped ) {
  1271. //
  1272. // Tell the netlogon service about the change.
  1273. //
  1274. Status = NlSendChangeLogNotification( ChangeLogLsaPolicyChanged,
  1275. NULL,
  1276. NULL,
  1277. (ULONG) ChangeInfoClass,
  1278. NULL, // Object GUID,
  1279. NULL, // Domain GUID,
  1280. NULL ); // Domain Name
  1281. //
  1282. // If the netlogon service is not running,
  1283. // handle operations that need handling here.
  1284. //
  1285. } else {
  1286. //
  1287. // Tell the browser about the change.
  1288. //
  1289. switch ( ChangeInfoClass ) {
  1290. case PolicyNotifyDnsDomainInformation:
  1291. //
  1292. // Tell the worker that it needs to notify the browser.
  1293. //
  1294. LOCK_CHANGELOG();
  1295. NlGlobalChangeLogNotifyBrowser = TRUE;
  1296. //
  1297. // Start the worker.
  1298. //
  1299. NlStartChangeLogWorkerThread();
  1300. UNLOCK_CHANGELOG();
  1301. }
  1302. }
  1303. return;
  1304. }
  1305. NTSTATUS
  1306. I_NetNotifyTrustedDomain (
  1307. IN PSID HostedDomainSid,
  1308. IN PSID TrustedDomainSid,
  1309. IN BOOLEAN IsDeletion
  1310. )
  1311. /*++
  1312. Routine Description:
  1313. This function is called by the LSA to indicate that a trusted domain
  1314. object has changed.
  1315. This function is called for both PDC and BDC.
  1316. Arguments:
  1317. HostedDomainSid - Domain SID of the domain the trust is from.
  1318. TrustedDomainSid - Domain SID of the domain the trust is to.
  1319. IsDeletion - TRUE if the trusted domain object was deleted.
  1320. FALSE if the trusted domain object was created or modified.
  1321. Return Value:
  1322. Status of the operation.
  1323. --*/
  1324. {
  1325. NTSTATUS Status;
  1326. //
  1327. // If the netlogon service isn't running,
  1328. // Don't bother with the coming and going of trusted domains..
  1329. //
  1330. if( NlGlobalChangeLogNetlogonState == NetlogonStopped ) {
  1331. return(STATUS_SUCCESS);
  1332. }
  1333. //
  1334. // If this is windows NT,
  1335. // There is nothing to maintain.
  1336. //
  1337. if ( NlGlobalChangeLogRole == ChangeLogMemberWorkstation ) {
  1338. return(STATUS_SUCCESS);
  1339. }
  1340. //
  1341. // Reset the TrustInfoUpToDate event so that any thread that wants to
  1342. // access the trust info list will wait until the info is updated (by
  1343. // the NlInitTrustList function).
  1344. //
  1345. if ( !ResetEvent( NlGlobalTrustInfoUpToDateEvent ) ) {
  1346. NlPrint((NL_CRITICAL,
  1347. "Cannot reset NlGlobalTrustInfoUpToDateEvent event: %lu\n",
  1348. GetLastError() ));
  1349. }
  1350. //
  1351. // Notify whether this is a creation/change/deletion.
  1352. if ( IsDeletion ) {
  1353. //
  1354. // Tell the netlogon service to update its in-memory list now.
  1355. //
  1356. Status = NlSendChangeLogNotification( ChangeLogTrustDeleted,
  1357. NULL,
  1358. TrustedDomainSid,
  1359. 0,
  1360. NULL, // Object GUID,
  1361. NULL, // Domain GUID,
  1362. NULL ); // Domain Name
  1363. } else {
  1364. //
  1365. // Tell the netlogon service to update its in-memory list now.
  1366. //
  1367. Status = NlSendChangeLogNotification( ChangeLogTrustAdded,
  1368. NULL,
  1369. TrustedDomainSid,
  1370. 0,
  1371. NULL, // Object GUID,
  1372. NULL, // Domain GUID,
  1373. NULL ); // Domain Name
  1374. }
  1375. return Status;
  1376. UNREFERENCED_PARAMETER( HostedDomainSid );
  1377. }
  1378. NTSTATUS
  1379. I_NetNotifyNtdsDsaDeletion (
  1380. IN LPWSTR DnsDomainName OPTIONAL,
  1381. IN GUID *DomainGuid OPTIONAL,
  1382. IN GUID *DsaGuid OPTIONAL,
  1383. IN LPWSTR DnsHostName
  1384. )
  1385. /*++
  1386. Routine Description:
  1387. This function is called by the DS to indicate that a NTDS-DSA object
  1388. and/or DNS records associated with the DNS host name are being deleted.
  1389. This function is called on the DC that the object is originally deleted on.
  1390. It is not called when the deletion is replicated to other DCs.
  1391. Arguments:
  1392. DnsDomainName - DNS domain name of the domain the DC was in.
  1393. This need not be a domain hosted by this DC.
  1394. If NULL, it is implied to be the DnsHostName with the leftmost label
  1395. removed.
  1396. DomainGuid - Domain Guid of the domain specified by DnsDomainName
  1397. If NULL, GUID specific names will not be removed.
  1398. DsaGuid - GUID of the NtdsDsa object that is being deleted.
  1399. DnsHostName - DNS host name of the DC whose NTDS-DSA object is being deleted.
  1400. Return Value:
  1401. Status of the operation.
  1402. --*/
  1403. {
  1404. NTSTATUS Status;
  1405. UNICODE_STRING DnsDomainNameString;
  1406. PUNICODE_STRING DnsDomainNameStringPtr = NULL;
  1407. UNICODE_STRING DnsHostNameString;
  1408. //
  1409. // If the netlogon service isn't running,
  1410. // Don't bother with the coming and going of trusted domains..
  1411. //
  1412. if( NlGlobalChangeLogNetlogonState == NetlogonStopped ) {
  1413. return(STATUS_SUCCESS);
  1414. }
  1415. //
  1416. // If this is windows NT,
  1417. // There is nothing to maintain.
  1418. //
  1419. if ( NlGlobalChangeLogRole == ChangeLogMemberWorkstation ) {
  1420. return(STATUS_SUCCESS);
  1421. }
  1422. //
  1423. // Queue this to the netlogon service
  1424. //
  1425. if ( DnsDomainName != NULL ) {
  1426. RtlInitUnicodeString( &DnsDomainNameString, DnsDomainName );
  1427. DnsDomainNameStringPtr = &DnsDomainNameString;
  1428. }
  1429. RtlInitUnicodeString( &DnsHostNameString, DnsHostName );
  1430. Status = NlSendChangeLogNotification( ChangeLogNtdsDsaDeleted,
  1431. &DnsHostNameString,
  1432. NULL,
  1433. 0,
  1434. DsaGuid,
  1435. DomainGuid,
  1436. DnsDomainNameStringPtr );
  1437. return Status;
  1438. }
  1439. NTSTATUS
  1440. I_NetLogonSetServiceBits(
  1441. IN DWORD ServiceBitsOfInterest,
  1442. IN DWORD ServiceBits
  1443. )
  1444. /*++
  1445. Routine Description:
  1446. Inidcates whether this DC is currently running the specified service.
  1447. For instance,
  1448. I_NetLogonSetServiceBits( DS_KDC_FLAG, DS_KDC_FLAG );
  1449. tells Netlogon the KDC is running. And
  1450. I_NetLogonSetServiceBits( DS_KDC_FLAG, 0 );
  1451. tells Netlogon the KDC is not running.
  1452. Arguments:
  1453. ServiceBitsOfInterest - A mask of the service bits being changed, set,
  1454. or reset by this call. Only the following flags are valid:
  1455. DS_KDC_FLAG
  1456. DS_DS_FLAG
  1457. DS_TIMESERV_FLAG
  1458. DS_GOOD_TIMESERV_FLAG
  1459. ServiceBits - A mask indicating what the bits specified by ServiceBitsOfInterest
  1460. should be set to.
  1461. Return Value:
  1462. STATUS_SUCCESS - Success.
  1463. STATUS_INVALID_PARAMETER - The parameters have extaneous bits set.
  1464. --*/
  1465. {
  1466. NTSTATUS Status = STATUS_SUCCESS;
  1467. ULONG OldDnsBits;
  1468. ULONG NewDnsBits;
  1469. //
  1470. // Ensure the caller passed valid bits.
  1471. //
  1472. if ( (ServiceBitsOfInterest & ~DS_VALID_SERVICE_BITS) != 0 ||
  1473. (ServiceBits & ~ServiceBitsOfInterest) != 0 ) {
  1474. return STATUS_INVALID_PARAMETER;
  1475. }
  1476. //
  1477. // Change the bits.
  1478. //
  1479. LOCK_CHANGELOG();
  1480. OldDnsBits = NlGlobalChangeLogServiceBits & DS_DNS_SERVICE_BITS;
  1481. NlGlobalChangeLogServiceBits &= ~ServiceBitsOfInterest;
  1482. NlGlobalChangeLogServiceBits |= ServiceBits;
  1483. NewDnsBits = NlGlobalChangeLogServiceBits & DS_DNS_SERVICE_BITS;
  1484. NlGlobalChangeLogDllUnloaded = FALSE;
  1485. UNLOCK_CHANGELOG();
  1486. //
  1487. // If bits changed that would affect which names we register in DNS,
  1488. // change the registration now.
  1489. //
  1490. if ( OldDnsBits != NewDnsBits ) {
  1491. //
  1492. // Tell the netlogon service to update now.
  1493. //
  1494. Status = NlSendChangeLogNotification( ChangeDnsNames,
  1495. NULL,
  1496. NULL,
  1497. 0, // Name registration need not be forced
  1498. NULL, // Object GUID,
  1499. NULL, // Domain GUID,
  1500. NULL ); // Domain Name
  1501. }
  1502. return Status;
  1503. }
  1504. NTSTATUS
  1505. NlInitChangeLog(
  1506. VOID
  1507. )
  1508. /*++
  1509. Routine Description:
  1510. Do the portion of ChangeLog initialization which happens on process
  1511. attach for netlogon.dll.
  1512. Specifically, Initialize the NlGlobalChangeLogCritSect and several
  1513. other global variables.
  1514. Arguments:
  1515. NONE
  1516. Return Value:
  1517. NT Status code
  1518. --*/
  1519. {
  1520. LARGE_INTEGER DomainPromotionIncrement = DOMAIN_PROMOTION_INCREMENT;
  1521. LARGE_INTEGER DomainPromotionMask = DOMAIN_PROMOTION_MASK;
  1522. NTSTATUS Status;
  1523. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  1524. NT_PRODUCT_TYPE NtProductType;
  1525. //
  1526. // Initialize the critical section and anything process detach depends on.
  1527. //
  1528. #if NETLOGONDBG
  1529. try {
  1530. InitializeCriticalSection(&NlGlobalLogFileCritSect);
  1531. } except( EXCEPTION_EXECUTE_HANDLER ) {
  1532. NlPrint((NL_CRITICAL, "Cannot InitializeCriticalSection for NlGlobalLogFileCritSect\n" ));
  1533. return STATUS_NO_MEMORY;
  1534. }
  1535. #endif // NETLOGONDBG
  1536. try {
  1537. InitializeCriticalSection( &NlGlobalChangeLogCritSect );
  1538. } except( EXCEPTION_EXECUTE_HANDLER ) {
  1539. NlPrint((NL_CRITICAL, "Cannot InitializeCriticalSection for NlGlobalChangeLogCritSect\n" ));
  1540. return STATUS_NO_MEMORY;
  1541. }
  1542. try {
  1543. InitializeCriticalSection( &NlGlobalSecPkgCritSect );
  1544. } except( EXCEPTION_EXECUTE_HANDLER ) {
  1545. NlPrint((NL_CRITICAL, "Cannot InitializeCriticalSection for NlGlobalSecPkgCritSect\n" ));
  1546. return STATUS_NO_MEMORY;
  1547. }
  1548. #if NETLOGONDBG
  1549. NlGlobalParameters.DbFlag = 0xFFFFFFFF;
  1550. NlGlobalLogFile = INVALID_HANDLE_VALUE;
  1551. NlGlobalParameters.LogFileMaxSize = DEFAULT_MAXIMUM_LOGFILE_SIZE;
  1552. NlGlobalLogFileOutputBuffer = NULL;
  1553. #endif // NETLOGONDBG
  1554. InitChangeLogDesc( &NlGlobalChangeLogDesc );
  1555. InitChangeLogDesc( &NlGlobalTempChangeLogDesc );
  1556. NlGlobalChangeLogBuiltinDomainSid = NULL;
  1557. NlGlobalChangeLogServiceBits = 0;
  1558. NlGlobalChangeLogWorkerThreadHandle = NULL;
  1559. NlGlobalChangeLogNotifyBrowser = FALSE;
  1560. NlGlobalChangeLogNotifyBrowserIsRunning = FALSE;
  1561. NlGlobalChangeLogWorkerIsRunning = FALSE;
  1562. NlGlobalChangeLogDllUnloaded = TRUE;
  1563. NlGlobalChangeLogNetlogonState = NetlogonStopped;
  1564. NlGlobalChangeLogEvent = NULL;
  1565. NlGlobalChangeLogReplicateImmediately = FALSE;
  1566. InitializeListHead( &NlGlobalChangeLogNotifications );
  1567. NlGlobalEventlogHandle = NetpEventlogOpen ( SERVICE_NETLOGON,
  1568. 0 ); // No timeout for now
  1569. if ( NlGlobalEventlogHandle == NULL ) {
  1570. NlPrint((NL_CRITICAL, "Cannot NetpEventlogOpen\n" ));
  1571. return STATUS_NO_MEMORY;
  1572. }
  1573. NlGlobalChangeLogFilePrefix[0] = L'\0';
  1574. NlGlobalChangeLogPromotionIncrement = DomainPromotionIncrement;
  1575. NlGlobalChangeLogPromotionMask = DomainPromotionMask.HighPart;
  1576. //
  1577. // Create special change log notify event.
  1578. //
  1579. NlGlobalChangeLogEvent =
  1580. CreateEvent( NULL, // No security attributes
  1581. FALSE, // Is automatically reset
  1582. FALSE, // Initially not signaled
  1583. NULL ); // No name
  1584. if ( NlGlobalChangeLogEvent == NULL ) {
  1585. NET_API_STATUS NetStatus;
  1586. NetStatus = GetLastError();
  1587. NlPrint((NL_CRITICAL, "Cannot create ChangeLog Event %lu\n",
  1588. NetStatus ));
  1589. return (int) NetpApiStatusToNtStatus(NetStatus);
  1590. }
  1591. //
  1592. // Create the trust-info-up-to-date event.
  1593. //
  1594. NlGlobalTrustInfoUpToDateEvent =
  1595. CreateEvent( NULL, // No security attributes
  1596. TRUE, // Is manually reset
  1597. TRUE, // Initially signaled
  1598. NULL ); // No name
  1599. if ( NlGlobalTrustInfoUpToDateEvent == NULL ) {
  1600. NET_API_STATUS NetStatus;
  1601. NetStatus = GetLastError();
  1602. NlPrint((NL_CRITICAL, "Cannot create TrustInfoUpToDate Event %lu\n",
  1603. NetStatus ));
  1604. return (int) NetpApiStatusToNtStatus(NetStatus);
  1605. }
  1606. //
  1607. // Initialize the Role.
  1608. //
  1609. // For Windows-NT, just set the role to member workstation once and for all.
  1610. //
  1611. // For LanMan-Nt initially set it to "unknown" to prevent the
  1612. // changelog from being maintained until LSA calls I_NetNotifyRole.
  1613. //
  1614. if ( !RtlGetNtProductType( &NtProductType ) ) {
  1615. NtProductType = NtProductWinNt;
  1616. }
  1617. if ( NtProductType == NtProductLanManNt ) {
  1618. NlGlobalChangeLogRole = ChangeLogUnknown;
  1619. } else {
  1620. NlGlobalChangeLogRole = ChangeLogMemberWorkstation;
  1621. }
  1622. //
  1623. // Initialize DC specific globals.
  1624. //
  1625. if ( NtProductType == NtProductLanManNt ) {
  1626. //
  1627. // Build a Sid for the SAM Builtin domain
  1628. //
  1629. Status = RtlAllocateAndInitializeSid(
  1630. &NtAuthority,
  1631. 1, // Sub Authority Count
  1632. SECURITY_BUILTIN_DOMAIN_RID,
  1633. 0, // Unused
  1634. 0, // Unused
  1635. 0, // Unused
  1636. 0, // Unused
  1637. 0, // Unused
  1638. 0, // Unused
  1639. 0, // Unused
  1640. &NlGlobalChangeLogBuiltinDomainSid);
  1641. if ( !NT_SUCCESS(Status) ) {
  1642. goto Cleanup;
  1643. }
  1644. }
  1645. //
  1646. // Ask the LSA to notify us of any changes to the LSA database.
  1647. //
  1648. Status = LsaIRegisterPolicyChangeNotificationCallback(
  1649. &I_NetNotifyLsaPolicyChange,
  1650. PolicyNotifyDnsDomainInformation );
  1651. if ( !NT_SUCCESS(Status) ) {
  1652. NlPrint((NL_CRITICAL,
  1653. "Failed to LsaIRegisterPolicyChangeNotificationCallback. %lX\n",
  1654. Status ));
  1655. goto Cleanup;
  1656. }
  1657. //
  1658. // Success...
  1659. //
  1660. Status = STATUS_SUCCESS;
  1661. //
  1662. // Cleanup
  1663. //
  1664. Cleanup:
  1665. return Status;
  1666. }
  1667. //
  1668. // netlogon.dll never detaches
  1669. //
  1670. #if NETLOGONDBG
  1671. NTSTATUS
  1672. NlCloseChangeLog(
  1673. VOID
  1674. )
  1675. /*++
  1676. Routine Description:
  1677. Frees any resources consumed by NlInitChangeLog.
  1678. Arguments:
  1679. NONE
  1680. Return Value:
  1681. NT Status code
  1682. --*/
  1683. {
  1684. NTSTATUS Status;
  1685. //
  1686. // Ask the LSA to notify us of any changes to the LSA database.
  1687. //
  1688. Status = LsaIUnregisterAllPolicyChangeNotificationCallback(
  1689. &I_NetNotifyLsaPolicyChange );
  1690. if ( !NT_SUCCESS(Status) ) {
  1691. NlPrint((NL_CRITICAL,
  1692. "Failed to LsaIUnregisterPolicyChangeNotificationCallback. %lX\n",
  1693. Status ));
  1694. }
  1695. if ( (NlGlobalChangeLogDesc.FileHandle == INVALID_HANDLE_VALUE) &&
  1696. (NlGlobalChangeLogRole == ChangeLogPrimary) ) {
  1697. //
  1698. // try to save change log cache one last time.
  1699. //
  1700. (VOID)NlCreateChangeLogFile( &NlGlobalChangeLogDesc );
  1701. }
  1702. //
  1703. // Close the changelogs
  1704. //
  1705. NlCloseChangeLogFile( &NlGlobalChangeLogDesc );
  1706. NlCloseChangeLogFile( &NlGlobalTempChangeLogDesc );
  1707. //
  1708. // Initialize the globals.
  1709. //
  1710. NlGlobalChangeLogFilePrefix[0] = L'\0';
  1711. if ( NlGlobalChangeLogBuiltinDomainSid != NULL ) {
  1712. RtlFreeSid( NlGlobalChangeLogBuiltinDomainSid );
  1713. NlGlobalChangeLogBuiltinDomainSid = NULL;
  1714. }
  1715. if ( NlGlobalChangeLogEvent != NULL ) {
  1716. (VOID) CloseHandle(NlGlobalChangeLogEvent);
  1717. NlGlobalChangeLogEvent = NULL;
  1718. }
  1719. if ( NlGlobalTrustInfoUpToDateEvent != NULL ) {
  1720. (VOID) CloseHandle(NlGlobalTrustInfoUpToDateEvent);
  1721. NlGlobalTrustInfoUpToDateEvent = NULL;
  1722. }
  1723. //
  1724. // Stop the worker thread if it is running
  1725. //
  1726. NlStopChangeLogWorker();
  1727. LOCK_CHANGELOG();
  1728. NlAssert( IsListEmpty( &NlGlobalChangeLogNotifications ) );
  1729. UNLOCK_CHANGELOG();
  1730. //
  1731. // Close the eventlog handle
  1732. //
  1733. NetpEventlogClose( NlGlobalEventlogHandle );
  1734. //
  1735. // close all handles
  1736. //
  1737. DeleteCriticalSection(&NlGlobalSecPkgCritSect);
  1738. DeleteCriticalSection( &NlGlobalChangeLogCritSect );
  1739. #if NETLOGONDBG
  1740. if ( NlGlobalLogFileOutputBuffer != NULL ) {
  1741. LocalFree( NlGlobalLogFileOutputBuffer );
  1742. NlGlobalLogFileOutputBuffer = NULL;
  1743. }
  1744. DeleteCriticalSection( &NlGlobalLogFileCritSect );
  1745. #endif // NETLOGONDBG
  1746. return STATUS_SUCCESS;
  1747. }
  1748. #endif // NETLOGONDBG