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.

1113 lines
28 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. Regnckey.c
  5. Abstract:
  6. This module contains the client side wrappers for the Win32 Registry
  7. APIs to notify a caller about a changed Key value. That is:
  8. - RegNotifyChangeKey
  9. Author:
  10. David J. Gilman (davegi) 10-Feb-1992
  11. Notes:
  12. The implementation of RegNotifyChangeKeyValue involves >= 4 threads: 2 on
  13. the client side and >= 2 on the server side.
  14. Client:
  15. Thread 1.- The user's thread executing the RegNotifyChangeKeyValue.
  16. This threads does:
  17. - If thread #2 has not been created yet, it creates a
  18. named pipe and thread #2.
  19. - Does a synchronous RPC to the server
  20. Thread 2.- This thread reads events from the named pipe and signals
  21. them. The writers to the pipe are the RPC servers which
  22. thread 1 has called.
  23. Server:
  24. Thread 1.- This thread services the RPC from the client side. It
  25. calls the NT notification API and adds the notification
  26. handle to a "notification list".
  27. Thread 2.- This thread waits on part of the "notification list",
  28. telling the original client (via named pipe) what events
  29. need to be signaled.
  30. Threads 3... etc. Same as thread 2.
  31. Revision History:
  32. 02-Apr-1992 Ramon J. San Andres (ramonsa)
  33. Changed to use RPC.
  34. --*/
  35. #include <rpc.h>
  36. #include "regrpc.h"
  37. #include "client.h"
  38. #include <stdlib.h>
  39. NTSTATUS BaseRegNotifyClassKey(
  40. IN HKEY hKey,
  41. IN HANDLE hEvent,
  42. IN PIO_STATUS_BLOCK pLocalIoStatusBlock,
  43. IN DWORD dwNotifyFilter,
  44. IN BOOLEAN fWatchSubtree,
  45. IN BOOLEAN fAsynchronous);
  46. //
  47. // Used by local call to NtNotifyChangeKey.
  48. //
  49. IO_STATUS_BLOCK LocalIoStatusBlock;
  50. #ifndef REMOTE_NOTIFICATION_DISABLED
  51. //
  52. // Named pipe full paths.
  53. //
  54. #define NAMED_PIPE_HERE L"\\Device\\NamedPipe\\"
  55. //
  56. // Maximum number of times we will retry to create a pipe if there are
  57. // name conflicts.
  58. //
  59. #define MAX_PIPE_RETRIES 1000
  60. //
  61. // Local variables.
  62. //
  63. //
  64. // Critical section to control access to notification structures
  65. //
  66. RTL_CRITICAL_SECTION NotificationCriticalSection;
  67. //
  68. // Our machine name
  69. //
  70. UNICODE_STRING OurMachineName;
  71. WCHAR OurMachineNameBuffer[ MAX_PATH ];
  72. //
  73. // Named pipe used for notification
  74. //
  75. UNICODE_STRING NotificationPipeName;
  76. WCHAR NotificationPipeNameBuffer[ MAX_PATH ];
  77. HANDLE NotificationPipeHandle;
  78. RPC_SECURITY_ATTRIBUTES NotificationPipeSaRpc;
  79. //
  80. // Security descriptor used in the named pipe
  81. //
  82. SECURITY_DESCRIPTOR SecurityDescriptor;
  83. PACL Acl;
  84. BOOL SecurityDescriptorInitialized;
  85. //
  86. // Notification thread
  87. //
  88. HANDLE NotificationThread;
  89. DWORD NotificationClientId;
  90. //
  91. // Local prototypes
  92. //
  93. LONG
  94. CreateNotificationPipe(
  95. );
  96. VOID
  97. NotificationHandler(
  98. );
  99. #endif // REMOTE_NOTIFICATION_DISABLED
  100. #ifndef REMOTE_NOTIFICATION_DISABLED
  101. LONG
  102. InitializeNotificationPipeSecurityDescriptor(
  103. )
  104. /*++
  105. Routine Description:
  106. Initialize the security descriptor (global variable) to be attached to
  107. the named pipe.
  108. Arguments:
  109. None
  110. Return Value:
  111. LONG - Returns a win32 error code.
  112. --*/
  113. {
  114. SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY;
  115. ULONG AclLength;
  116. PSID WorldSid;
  117. NTSTATUS NtStatus;
  118. //
  119. // Initialize global variables
  120. //
  121. SecurityDescriptorInitialized = FALSE;
  122. Acl = NULL;
  123. //
  124. // Get World SID
  125. //
  126. NtStatus = RtlAllocateAndInitializeSid( &WorldSidAuthority,
  127. 1,
  128. SECURITY_WORLD_RID,
  129. 0, 0, 0, 0, 0, 0, 0,
  130. &WorldSid
  131. );
  132. ASSERT( NT_SUCCESS( NtStatus ) );
  133. if ( !NT_SUCCESS( NtStatus )) {
  134. #if DBG
  135. DbgPrint( "WINREG: Unable to allocate and initialize SID, NtStatus = %x \n", NtStatus );
  136. #endif
  137. return( RtlNtStatusToDosError( NtStatus ) );
  138. }
  139. //
  140. // Allocate buffer for ACL.
  141. // This buffer should be big enough for the ACL header and for each ACE.
  142. // Each ACE needs an ACE header.
  143. //
  144. AclLength = sizeof( ACL ) +
  145. sizeof( ACCESS_ALLOWED_ACE ) +
  146. GetLengthSid( WorldSid ) +
  147. sizeof( DWORD );
  148. Acl = RtlAllocateHeap( RtlProcessHeap(), 0, AclLength );
  149. ASSERT( Acl != NULL );
  150. if( Acl == NULL ) {
  151. #if DBG
  152. DbgPrint( "WINREG: Unable to allocate memory, NtStatus = %x \n", NtStatus );
  153. #endif
  154. RtlFreeSid( WorldSid );
  155. return( ERROR_OUTOFMEMORY );
  156. }
  157. //
  158. // Build ACL: World has all access
  159. //
  160. NtStatus = RtlCreateAcl( (PACL)Acl,
  161. AclLength,
  162. ACL_REVISION2
  163. );
  164. ASSERT( NT_SUCCESS( NtStatus ) );
  165. if ( !NT_SUCCESS( NtStatus )) {
  166. #if DBG
  167. DbgPrint( "WINREG: Unable to create ACL, NtStatus = %x \n", NtStatus );
  168. #endif
  169. RtlFreeSid( WorldSid );
  170. RtlFreeHeap( RtlProcessHeap(), 0, Acl );
  171. return( RtlNtStatusToDosError( NtStatus ) );
  172. }
  173. NtStatus = RtlAddAccessAllowedAce( (PACL)Acl,
  174. ACL_REVISION2,
  175. SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE,
  176. WorldSid
  177. );
  178. RtlFreeSid( WorldSid );
  179. ASSERT( NT_SUCCESS( NtStatus ) );
  180. if ( !NT_SUCCESS( NtStatus )) {
  181. #if DBG
  182. DbgPrint( "WINREG: Unable to add ACE, NtStatus = %x \n", NtStatus );
  183. #endif
  184. RtlFreeHeap( RtlProcessHeap(), 0, Acl );
  185. return( RtlNtStatusToDosError( NtStatus ) );
  186. }
  187. //
  188. // Build security descriptor
  189. //
  190. NtStatus = RtlCreateSecurityDescriptor( &SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION );
  191. ASSERT( NT_SUCCESS( NtStatus ) );
  192. if ( !NT_SUCCESS( NtStatus )) {
  193. #if DBG
  194. DbgPrint( "WINREG: Unable to create security descriptor, NtStatus = %x \n", NtStatus );
  195. #endif
  196. RtlFreeHeap( RtlProcessHeap(), 0, Acl );
  197. return( RtlNtStatusToDosError( NtStatus ) );
  198. }
  199. #if DBG
  200. if( !RtlValidAcl( (PACL )Acl ) ) {
  201. DbgPrint( "WINREG: Acl is invalid \n" );
  202. RtlFreeHeap( RtlProcessHeap(), 0, Acl );
  203. return( ERROR_INVALID_ACL );
  204. }
  205. #endif
  206. NtStatus = RtlSetDaclSecurityDescriptor ( &SecurityDescriptor,
  207. TRUE,
  208. (PACL)Acl,
  209. FALSE
  210. );
  211. ASSERT( NT_SUCCESS( NtStatus ) );
  212. if ( !NT_SUCCESS( NtStatus )) {
  213. #if DBG
  214. DbgPrint( "WINREG: Unable to set DACL, NtStatus = %x \n", NtStatus );
  215. #endif
  216. RtlFreeHeap( RtlProcessHeap(), 0, Acl );
  217. return( RtlNtStatusToDosError( NtStatus ) );
  218. }
  219. SecurityDescriptorInitialized = TRUE;
  220. return( ERROR_SUCCESS );
  221. }
  222. BOOL
  223. InitializeRegNotifyChangeKeyValue(
  224. )
  225. /*++
  226. Routine Description:
  227. Initializes the static data structures used by the
  228. RegNotifyChangeKeyValue client. Called once at DLL
  229. initialization.
  230. Arguments:
  231. None
  232. Return Value:
  233. BOOLEAN - TRUE if successful.
  234. --*/
  235. {
  236. NTSTATUS NtStatus;
  237. NtStatus = RtlInitializeCriticalSection(
  238. &NotificationCriticalSection
  239. );
  240. if ( NT_SUCCESS( NtStatus ) ) {
  241. //
  242. // Initialize our machine name. Note that the actual
  243. // name is only obtained when the notification API
  244. // is first invoked.
  245. //
  246. OurMachineName.Length = 0;
  247. OurMachineName.MaximumLength = MAX_PATH * sizeof(WCHAR);
  248. OurMachineName.Buffer = OurMachineNameBuffer;
  249. //
  250. // Initialize named pipe data
  251. //
  252. NotificationPipeName.Length = 0;
  253. NotificationPipeName.MaximumLength = MAX_PATH * sizeof(WCHAR);
  254. NotificationPipeName.Buffer = NotificationPipeNameBuffer;
  255. NotificationThread = NULL;
  256. NotificationPipeHandle = NULL;
  257. NotificationPipeSaRpc.RpcSecurityDescriptor.lpSecurityDescriptor = NULL;
  258. return TRUE;
  259. }
  260. return FALSE;
  261. }
  262. BOOL
  263. CleanupRegNotifyChangeKeyValue(
  264. )
  265. /*++
  266. Routine Description:
  267. Performs any cleanup of the static data structures used
  268. by the RegNotifyChangeKeyValue client. Called once at
  269. process termination.
  270. Arguments:
  271. None
  272. Return Value:
  273. BOOLEAN - TRUE if successful.
  274. --*/
  275. {
  276. NTSTATUS NtStatus;
  277. //
  278. // Terminate notification thread if there is one running
  279. //
  280. if ( NotificationThread != NULL ) {
  281. //
  282. // Close the named pipe
  283. //
  284. if ( NotificationPipeHandle != NULL ) {
  285. NtStatus = NtClose( NotificationPipeHandle );
  286. ASSERT( NT_SUCCESS( NtStatus ) );
  287. }
  288. TerminateThread( NotificationThread, 0 );
  289. }
  290. //
  291. // Delete the notification critical section
  292. //
  293. NtStatus = RtlDeleteCriticalSection(
  294. &NotificationCriticalSection
  295. );
  296. ASSERT( NT_SUCCESS( NtStatus ) );
  297. if ( NotificationPipeSaRpc.RpcSecurityDescriptor.lpSecurityDescriptor ) {
  298. RtlFreeHeap(
  299. RtlProcessHeap( ), 0,
  300. NotificationPipeSaRpc.RpcSecurityDescriptor.lpSecurityDescriptor
  301. );
  302. }
  303. return TRUE;
  304. }
  305. #endif // REMOTE_NOTIFICATION_DISABLED
  306. LONG
  307. RegNotifyChangeKeyValue(
  308. HKEY hKey,
  309. BOOL fWatchSubtree,
  310. DWORD dwNotifyFilter,
  311. HANDLE hEvent,
  312. BOOL fAsynchronous
  313. )
  314. /*++
  315. Routine Description:
  316. This API is used to watch a key or sub-tree for changes. It can be
  317. called either synchronously or asynchronously. In the latter case the
  318. caller must supply an event that is signalled when changes occur. In
  319. either case it is possible to filter the criteria by which the
  320. notification occurs.
  321. Arguments:
  322. hKey - Supplies a handle to a key that has been previously opened with
  323. KEY_NOTIFY access.
  324. fWatchSubtree - Supplies a boolean value that if TRUE causes the
  325. system to monitor the key and all of its decsendants. A value of
  326. FALSE causes the system to monitor only the specified key.
  327. dwNotifyFilter - Supplies a set of flags that specify the filter
  328. conditions the system uses to satisfy a change notification.
  329. REG_NOTIFY_CHANGE_KEYNAME - Any key name changes that occur
  330. in a key or subtree being watched will satisfy a
  331. change notification wait. This includes creations
  332. and deletions.
  333. REG_NOTIFY_CHANGE_ATTRIBUTES - Any attribute changes that occur
  334. in a key or subtree being watched will satisfy a
  335. change notification.
  336. REG_NOTIFY_CHANGE_LAST_WRITE - Any last write time changes that
  337. occur in a key or subtree being watched will satisfy a
  338. change notification.
  339. REG_NOTIFY_CHANGE_SECURITY - Any security descriptor changes
  340. that occur in a key or subtree being watched will
  341. satisfy a change notification.
  342. hEvent - Supplies an optional event handle. This parameter is ignored
  343. if fAsynchronus is set to FALSE.
  344. fAsynchronous - Supplies a flag which if FALSE causes the API to not
  345. return until something has changed. If TRUE, the API returns
  346. immediately and changes are reported via the supplied event. It
  347. is an error for this parameter to be TRUE and hEvent to be NULL.
  348. Return Value:
  349. LONG - Returns ERROR_SUCCESS (0); error-code for failure.
  350. Notes:
  351. If the supplied hKey is closed the event is signalled.
  352. Therefore it is possible to return from a wait on the event and then
  353. have subsequent APIs fail.
  354. --*/
  355. {
  356. HKEY Handle;
  357. HANDLE EventHandle;
  358. LONG Error = ERROR_SUCCESS;
  359. NTSTATUS NtStatus;
  360. PRPC_SECURITY_ATTRIBUTES pRpcSa;
  361. HKEY TempHandle = NULL;
  362. #if DBG
  363. if ( BreakPointOnEntry ) {
  364. DbgBreakPoint();
  365. }
  366. #endif
  367. //
  368. // Limit the capabilities associated with HKEY_PERFORMANCE_DATA.
  369. //
  370. if( hKey == HKEY_PERFORMANCE_DATA ) {
  371. return ERROR_INVALID_HANDLE;
  372. }
  373. //
  374. // Validate the dependency between fAsynchronus and hEvent.
  375. //
  376. if (( fAsynchronous ) && ( ! ARGUMENT_PRESENT( hEvent ))) {
  377. return ERROR_INVALID_PARAMETER;
  378. }
  379. Handle = MapPredefinedHandle( hKey, &TempHandle );
  380. if ( Handle == NULL ) {
  381. CLOSE_LOCAL_HANDLE(TempHandle);
  382. return ERROR_INVALID_HANDLE;
  383. }
  384. //
  385. // Notification is not supported on remote handles.
  386. //
  387. if( !IsLocalHandle( Handle ) ) {
  388. CLOSE_LOCAL_HANDLE(TempHandle);
  389. return ERROR_INVALID_HANDLE;
  390. } else {
  391. //
  392. // If its a local handle, make an Nt API call and return.
  393. //
  394. if (IsSpecialClassesHandle( Handle )) {
  395. //
  396. // We call a special function for class keys
  397. //
  398. NtStatus = BaseRegNotifyClassKey(
  399. Handle,
  400. hEvent,
  401. &LocalIoStatusBlock,
  402. dwNotifyFilter,
  403. ( BOOLEAN ) fWatchSubtree,
  404. ( BOOLEAN ) fAsynchronous
  405. );
  406. } else {
  407. NtStatus = NtNotifyChangeKey(
  408. Handle,
  409. hEvent,
  410. NULL,
  411. NULL,
  412. &LocalIoStatusBlock,
  413. dwNotifyFilter,
  414. ( BOOLEAN ) fWatchSubtree,
  415. NULL,
  416. 0,
  417. ( BOOLEAN ) fAsynchronous
  418. );
  419. }
  420. if( NT_SUCCESS( NtStatus ) ||
  421. ( NtStatus == STATUS_PENDING ) ) {
  422. Error = (error_status_t)ERROR_SUCCESS;
  423. } else {
  424. Error = (error_status_t) RtlNtStatusToDosError( NtStatus );
  425. }
  426. CLOSE_LOCAL_HANDLE(TempHandle);
  427. return Error;
  428. }
  429. #ifndef REMOTE_NOTIFICATION_DISABLED
  430. // NOTE: THE FOLLOWING CODE IS DISABLED BY THE CHECK FOR
  431. // IsLocalHandle AT THE BEGINNING OF THE FUNCTION.
  432. //
  433. //
  434. // If this is an asynchronous call, we use the user-provided
  435. // event and will let the user wait on it him/herself.
  436. // Otherwise we have to create our own event and wait on
  437. // it ourselves.
  438. //
  439. // This is because the server side of the API is always
  440. // asynchronous.
  441. //
  442. if ( fAsynchronous ) {
  443. EventHandle = hEvent;
  444. } else {
  445. NtStatus = NtCreateEvent(
  446. &EventHandle,
  447. EVENT_ALL_ACCESS,
  448. NULL,
  449. NotificationEvent,
  450. FALSE
  451. );
  452. if ( !NT_SUCCESS( NtStatus ) ) {
  453. return RtlNtStatusToDosError( NtStatus );
  454. }
  455. }
  456. //
  457. // See if the notification thread is already running
  458. // and create it if not. We have to protect this
  459. // with a critical section because there might be
  460. // several instances of this API doing this check
  461. // at the same time.
  462. //
  463. NtStatus = RtlEnterCriticalSection( &NotificationCriticalSection );
  464. if ( !NT_SUCCESS( NtStatus ) ) {
  465. Error = RtlNtStatusToDosError( NtStatus );
  466. } else {
  467. //
  468. // We are now inside the critical section
  469. //
  470. if ( NotificationThread == NULL ) {
  471. //
  472. // Create a named pipe for the notification thread
  473. // to use.
  474. //
  475. Error = CreateNotificationPipe( );
  476. if ( Error == ERROR_SUCCESS ) {
  477. //
  478. // Create the notification thread
  479. //
  480. NotificationThread = CreateThread(
  481. NULL,
  482. (16 * 1024),
  483. (LPTHREAD_START_ROUTINE)NotificationHandler,
  484. NULL,
  485. 0,
  486. &NotificationClientId
  487. );
  488. if ( NotificationThread == NULL ) {
  489. //
  490. // Could not create thread, remove the named pipe.
  491. //
  492. Error = GetLastError();
  493. NtClose( NotificationPipeHandle );
  494. }
  495. }
  496. }
  497. NtStatus = RtlLeaveCriticalSection( &NotificationCriticalSection );
  498. ASSERT( NT_SUCCESS( NtStatus ) );
  499. }
  500. if ( Error == ERROR_SUCCESS ) {
  501. //
  502. // Let the server side do its work. Remember that this call
  503. // is always asynchronous.
  504. //
  505. if ( NotificationPipeSaRpc.RpcSecurityDescriptor.lpSecurityDescriptor ) {
  506. pRpcSa = &NotificationPipeSaRpc;
  507. } else {
  508. pRpcSa = NULL;
  509. }
  510. //NotificationPipeName.Length += sizeof(UNICODE_NULL);
  511. //OurMachineName.Length += sizeof(UNICODE_NULL );
  512. // DbgPrint(" Waiting for notification, handle %x\n", EventHandle );
  513. Error = (LONG)BaseRegNotifyChangeKeyValue(
  514. DereferenceRemoteHandle( Handle ),
  515. (BOOLEAN)fWatchSubtree,
  516. dwNotifyFilter,
  517. (DWORD)EventHandle,
  518. &OurMachineName,
  519. &NotificationPipeName,
  520. pRpcSa
  521. );
  522. //NotificationPipeName.Length -= sizeof(UNICODE_NULL);
  523. //OurMachineName.Length -= sizeof(UNICODE_NULL );
  524. }
  525. //
  526. // If the call went ok. and we are in synchronous mode, we have
  527. // to wait on the event.
  528. //
  529. if ( (Error == ERROR_SUCCESS) && !fAsynchronous ) {
  530. NtStatus = NtWaitForSingleObject(
  531. EventHandle,
  532. FALSE,
  533. NULL
  534. );
  535. if ( !NT_SUCCESS( NtStatus ) ) {
  536. Error = RtlNtStatusToDosError( NtStatus );
  537. }
  538. }
  539. //
  540. // If we created an event, we must close it now.
  541. //
  542. if ( !fAsynchronous ) {
  543. NtStatus = NtClose( EventHandle );
  544. ASSERT( NT_SUCCESS( NtStatus ));
  545. }
  546. return Error;
  547. #endif // REMOTE_NOTIFICATION_DISABLED
  548. }
  549. #ifndef REMOTE_NOTIFICATION_DISABLED
  550. LONG
  551. CreateNotificationPipe(
  552. )
  553. /*++
  554. Routine Description:
  555. Creates the notification named pipe and sets the appropriate
  556. global variables.
  557. Note that the NotificationPipeName set by this function is
  558. server-relative, so that no conversion is required on the
  559. server side.
  560. Arguments:
  561. None
  562. Return Value:
  563. Error code.
  564. --*/
  565. {
  566. UNICODE_STRING PipeName;
  567. WCHAR PipeNameBuffer[ MAX_PATH ];
  568. USHORT OrgSize;
  569. DWORD Sequence;
  570. NTSTATUS NtStatus;
  571. LARGE_INTEGER Timeout;
  572. OBJECT_ATTRIBUTES Obja;
  573. IO_STATUS_BLOCK IoStatusBlock;
  574. DWORD MachineNameLength;
  575. LONG WinStatus;
  576. //
  577. // Get our machine name
  578. //
  579. MachineNameLength = MAX_PATH;
  580. if ( !GetComputerNameW( OurMachineNameBuffer, &MachineNameLength ) ) {
  581. return GetLastError();
  582. }
  583. OurMachineName.Buffer = OurMachineNameBuffer;
  584. OurMachineName.Length = (USHORT)(MachineNameLength * sizeof(WCHAR));
  585. OurMachineName.MaximumLength = (USHORT)(MAX_PATH * sizeof(WCHAR));
  586. //
  587. // Get the "here" name
  588. //
  589. RtlMoveMemory(
  590. PipeNameBuffer,
  591. NAMED_PIPE_HERE,
  592. sizeof( NAMED_PIPE_HERE)
  593. );
  594. PipeName.MaximumLength = MAX_PATH * sizeof(WCHAR);
  595. PipeName.Buffer = PipeNameBuffer;
  596. //
  597. // Remember the size of the base portion of the pipe name, so
  598. // we can patch it later when we attempt to create the full
  599. // name.
  600. //
  601. OrgSize = (USHORT)(sizeof(NAMED_PIPE_HERE) - sizeof(UNICODE_NULL));
  602. //
  603. // Create the named pipe, if the name is already being used,
  604. // keep trying with different names.
  605. //
  606. Sequence = 0;
  607. Timeout.QuadPart = Int32x32To64( -10 * 1000, 50 );
  608. //
  609. // Initialize the security descriptor that will be set in the named pipe
  610. //
  611. WinStatus = InitializeNotificationPipeSecurityDescriptor();
  612. if( WinStatus != ERROR_SUCCESS ) {
  613. return( WinStatus );
  614. }
  615. do {
  616. //
  617. // Get a semi-unique name
  618. //
  619. if ( !MakeSemiUniqueName( &NotificationPipeName, Sequence++ ) ) {
  620. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  621. break;
  622. }
  623. //
  624. // Patch the full pipe name, in case this is not our first
  625. // try.
  626. //
  627. PipeName.Buffer[OrgSize/sizeof(WCHAR)] = UNICODE_NULL;
  628. PipeName.Length = OrgSize;
  629. //
  630. // Now get the full path of the pipe name
  631. //
  632. NtStatus = RtlAppendUnicodeStringToString(
  633. &PipeName,
  634. &NotificationPipeName
  635. );
  636. ASSERT( NT_SUCCESS( NtStatus ) );
  637. if ( !NT_SUCCESS( NtStatus ) ) {
  638. break;
  639. }
  640. InitializeObjectAttributes(
  641. &Obja,
  642. &PipeName,
  643. OBJ_CASE_INSENSITIVE,
  644. NULL,
  645. NULL
  646. );
  647. if( SecurityDescriptorInitialized ) {
  648. Obja.SecurityDescriptor = &SecurityDescriptor;
  649. }
  650. NtStatus = NtCreateNamedPipeFile (
  651. &NotificationPipeHandle,
  652. SYNCHRONIZE | GENERIC_READ | FILE_WRITE_ATTRIBUTES,
  653. &Obja,
  654. &IoStatusBlock,
  655. FILE_SHARE_WRITE | FILE_SHARE_READ,
  656. FILE_CREATE,
  657. FILE_SYNCHRONOUS_IO_NONALERT,
  658. FILE_PIPE_MESSAGE_TYPE,
  659. FILE_PIPE_MESSAGE_MODE,
  660. FILE_PIPE_QUEUE_OPERATION,
  661. 1,
  662. 0,
  663. 0,
  664. &Timeout
  665. );
  666. } while ( (NtStatus == STATUS_OBJECT_NAME_EXISTS) &&
  667. (Sequence <= MAX_PIPE_RETRIES )
  668. );
  669. //
  670. // At this point we don't need the security descriptor anymore.
  671. // Free the memory allocated for the ACL
  672. //
  673. if( SecurityDescriptorInitialized ) {
  674. RtlFreeHeap( RtlProcessHeap( ), 0, Acl );
  675. Acl = NULL;
  676. SecurityDescriptorInitialized = FALSE;
  677. }
  678. if ( !NT_SUCCESS( NtStatus ) ) {
  679. return RtlNtStatusToDosError( NtStatus );
  680. }
  681. NotificationPipeName.Length += sizeof(UNICODE_NULL);
  682. OurMachineName.Length += sizeof(UNICODE_NULL );
  683. return ERROR_SUCCESS;
  684. }
  685. VOID
  686. NotificationHandler(
  687. )
  688. /*++
  689. Routine Description:
  690. This function is the entry point of the notification thread.
  691. The notification thread is created the first time that
  692. the RegNotifyChangeKeyValue API is called by the process,
  693. and keeps on running until the process terminates.
  694. This function creates a named pipe whose name is given by
  695. RegNotifyChangeKeyValue to all its servers. The servers
  696. then use the pipe to indicate that a particular event has
  697. to be signaled.
  698. 117
  699. Note that this single thread is in charge of signaling the
  700. events for all the RegNotifyChangeKeyValue invocations of
  701. the process. However no state has to be maintained by this
  702. thread because all the state information is provided by the
  703. server through the named pipe.
  704. Arguments:
  705. None
  706. Return Value:
  707. None
  708. --*/
  709. {
  710. NTSTATUS NtStatus;
  711. IO_STATUS_BLOCK IoStatusBlock;
  712. HANDLE EventHandle;
  713. ASSERT( NotificationPipeHandle != NULL );
  714. while ( TRUE ) {
  715. //
  716. // Wait for a connection
  717. //
  718. NtStatus = NtFsControlFile(
  719. NotificationPipeHandle,
  720. NULL,
  721. NULL,
  722. NULL,
  723. &IoStatusBlock,
  724. FSCTL_PIPE_LISTEN,
  725. NULL,
  726. 0,
  727. NULL,
  728. 0
  729. );
  730. if ( NtStatus == STATUS_PENDING ) {
  731. NtStatus = NtWaitForSingleObject(
  732. NotificationPipeHandle,
  733. FALSE,
  734. NULL
  735. );
  736. }
  737. if ( NT_SUCCESS( NtStatus ) ||
  738. ( NtStatus == STATUS_PIPE_CONNECTED ) ) {
  739. //
  740. // Read an event handle from the pipe
  741. //
  742. NtStatus = NtReadFile(
  743. NotificationPipeHandle,
  744. NULL,
  745. NULL,
  746. NULL,
  747. &IoStatusBlock,
  748. ( PVOID )&EventHandle,
  749. sizeof( HANDLE ),
  750. NULL,
  751. NULL
  752. );
  753. if ( NtStatus == STATUS_PENDING ) {
  754. NtStatus = NtWaitForSingleObject(
  755. NotificationPipeHandle,
  756. FALSE,
  757. NULL
  758. );
  759. }
  760. //
  761. // Signal the Event.
  762. //
  763. if ( NT_SUCCESS( NtStatus ) ) {
  764. ASSERT( IoStatusBlock.Information == sizeof( HANDLE ) );
  765. //
  766. // Signal the event
  767. //
  768. //DbgPrint(" WINREG: Signaling handle %x\n", EventHandle );
  769. NtStatus = NtSetEvent( EventHandle, NULL );
  770. #if DBG
  771. if ( !NT_SUCCESS( NtStatus ) ) {
  772. DbgPrint( "WINREG: Cannot signal notification event 0x%x, status %x\n",
  773. EventHandle, NtStatus );
  774. }
  775. #endif
  776. ASSERT( NT_SUCCESS( NtStatus ) );
  777. } else if ( NtStatus != STATUS_PIPE_BROKEN ) {
  778. #if DBG
  779. DbgPrint( "WINREG (Notification handler) error reading pipe\n" );
  780. DbgPrint( " status 0x%x\n", NtStatus );
  781. #endif
  782. ASSERT( NT_SUCCESS( NtStatus ) );
  783. }
  784. } else if ( NtStatus != STATUS_PIPE_BROKEN &&
  785. NtStatus != STATUS_PIPE_CLOSING) {
  786. #if DBG
  787. DbgPrint( "WINREG (Notification): FsControlFile (Connect) status 0x%x\n",
  788. NtStatus );
  789. #endif
  790. }
  791. if ( NT_SUCCESS( NtStatus ) ||
  792. NtStatus == STATUS_PIPE_BROKEN ||
  793. NtStatus == STATUS_PIPE_CLOSING ||
  794. NtStatus == STATUS_PIPE_LISTENING ||
  795. NtStatus == STATUS_PIPE_BUSY ) {
  796. //
  797. // Disconnect
  798. //
  799. NtStatus = NtFsControlFile(
  800. NotificationPipeHandle,
  801. NULL,
  802. NULL,
  803. NULL,
  804. &IoStatusBlock,
  805. FSCTL_PIPE_DISCONNECT,
  806. NULL,
  807. 0,
  808. NULL,
  809. 0
  810. );
  811. if ( NtStatus == STATUS_PENDING) {
  812. NtStatus = NtWaitForSingleObject(
  813. NotificationPipeHandle,
  814. FALSE,
  815. NULL
  816. );
  817. }
  818. #if DBG
  819. if ( !NT_SUCCESS( NtStatus ) ) {
  820. DbgPrint( "WINREG (Notification): FsControlFile (Disconnect) status 0x%x\n",
  821. NtStatus );
  822. }
  823. #endif
  824. ASSERT( NT_SUCCESS( NtStatus ) );
  825. }
  826. }
  827. }
  828. #endif // REMOTE_NOTIFICATION_DISABLED