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.

729 lines
18 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. dbnotify.c
  5. Abstract:
  6. Implemntation of the LSA routines for notifying in processes callers when data changes
  7. Author:
  8. Mac McLain (MacM) May 22, 1997
  9. Environment:
  10. User Mode
  11. Revision History:
  12. --*/
  13. #include <lsapch2.h>
  14. #include <dbp.h>
  15. //
  16. // Global notification list
  17. //
  18. LSAP_POLICY_NOTIFICATION_LIST LsaPolicyChangeNotificationList[ PolicyNotifyMachineAccountPasswordInformation + 1 ];
  19. SAFE_RESOURCE LsaPolicyChangeNotificationLock;
  20. #define LSAP_NOTIFY_MAXIMUM_PER_CLASS 1000
  21. //
  22. // Local prototypes
  23. //
  24. DWORD
  25. WINAPI LsapNotifyChangeNotificationThread(
  26. LPVOID Parameter
  27. );
  28. NTSTATUS
  29. LsapInitializeNotifiyList(
  30. VOID
  31. )
  32. /*++
  33. Routine Description:
  34. Intializes the list of policy notification lists
  35. Arguments:
  36. VOID
  37. Return Value:
  38. VOID
  39. --*/
  40. {
  41. ULONG i;
  42. NTSTATUS Status ;
  43. for ( i = 0;
  44. i < sizeof( LsaPolicyChangeNotificationList ) / sizeof( LSAP_POLICY_NOTIFICATION_LIST );
  45. i++ ) {
  46. InitializeListHead( &( LsaPolicyChangeNotificationList[ i ].List ) );
  47. LsaPolicyChangeNotificationList[ i ].Callbacks = 0;
  48. }
  49. try
  50. {
  51. SafeInitializeResource( &LsaPolicyChangeNotificationLock, ( DWORD )POLICY_CHANGE_NOTIFICATION_LOCK_ENUM );
  52. Status = STATUS_SUCCESS ;
  53. }
  54. except ( EXCEPTION_EXECUTE_HANDLER )
  55. {
  56. Status = GetExceptionCode();
  57. }
  58. return Status ;
  59. }
  60. NTSTATUS
  61. LsapNotifyAddCallbackToList(
  62. IN PLSAP_POLICY_NOTIFICATION_LIST List,
  63. IN OPTIONAL pfLsaPolicyChangeNotificationCallback Callback,
  64. IN OPTIONAL HANDLE NotificationEvent,
  65. IN OPTIONAL ULONG OwnerProcess,
  66. IN OPTIONAL HANDLE OwnerEvent
  67. )
  68. /*++
  69. Routine Description:
  70. This function inserts a new callback node into the existing list.
  71. Arguments:
  72. List -- Existing list
  73. Callback -- Callback function pointer. Can be NULL if NotificationEvent is provided
  74. NotificationEvent - Handle to an event to be signalled for notification. Can be NULL if
  75. Callback is provided.
  76. Return Value:
  77. STATUS_SUCCESS -- Success
  78. STATUS_INSUFFICIENT_RESOURCES -- A memory allocation failed.
  79. --*/
  80. {
  81. NTSTATUS Status = STATUS_SUCCESS;
  82. PLSAP_POLICY_NOTIFICATION_ENTRY NewEntry = NULL;
  83. NewEntry = LsapAllocateLsaHeap( sizeof( LSAP_POLICY_NOTIFICATION_ENTRY ) );
  84. if ( !NewEntry ) {
  85. return STATUS_INSUFFICIENT_RESOURCES;
  86. }
  87. if ( !SafeAcquireResourceExclusive( &LsaPolicyChangeNotificationLock, TRUE ) ) {
  88. LsapFreeLsaHeap( NewEntry );
  89. return( STATUS_UNSUCCESSFUL );
  90. }
  91. if ( List->Callbacks < LSAP_NOTIFY_MAXIMUM_PER_CLASS ) {
  92. InsertTailList( &List->List, &NewEntry->List );
  93. NewEntry->NotificationCallback = Callback;
  94. NewEntry->NotificationEvent = NotificationEvent;
  95. NewEntry->HandleInvalid = FALSE;
  96. NewEntry->OwnerProcess = OwnerProcess;
  97. NewEntry->OwnerEvent = OwnerEvent;
  98. List->Callbacks++;
  99. }
  100. SafeReleaseResource( &LsaPolicyChangeNotificationLock );
  101. return( Status );
  102. }
  103. NTSTATUS
  104. LsapNotifyRemoveCallbackFromList(
  105. IN PLSAP_POLICY_NOTIFICATION_LIST List,
  106. IN OPTIONAL pfLsaPolicyChangeNotificationCallback Callback,
  107. IN OPTIONAL ULONG OwnerProcess,
  108. IN OPTIONAL HANDLE OwnerEvent
  109. )
  110. /*++
  111. Routine Description:
  112. This function inserts a new callback node into the existing list.
  113. Arguments:
  114. List -- Existing list
  115. Callback -- Callback function pointer. Can be NULL if a notification event is provided
  116. NotificationEvent -- Notification event handle to be revomed. Can be NULL if a callback
  117. is provided
  118. Return Value:
  119. STATUS_SUCCESS -- Success
  120. STATUS_NOT_FOUND -- The supplied callback was not found in the specified list
  121. --*/
  122. {
  123. NTSTATUS Status = STATUS_NOT_FOUND;
  124. ULONG i;
  125. PLSAP_POLICY_NOTIFICATION_ENTRY Entry;
  126. if ( !SafeAcquireResourceExclusive( &LsaPolicyChangeNotificationLock, TRUE ) ) {
  127. return( STATUS_UNSUCCESSFUL );
  128. }
  129. Entry = (PLSAP_POLICY_NOTIFICATION_ENTRY)List->List.Flink;
  130. for ( i = 0; i < List->Callbacks; i++ ) {
  131. if ( Entry->NotificationCallback == Callback &&
  132. Entry->OwnerProcess == OwnerProcess &&
  133. Entry->OwnerEvent == OwnerEvent ) {
  134. List->Callbacks--;
  135. RemoveEntryList( &Entry->List );
  136. if ( Entry->NotificationEvent != NULL &&
  137. Entry->NotificationEvent != INVALID_HANDLE_VALUE ) {
  138. NtClose( Entry->NotificationEvent );
  139. }
  140. LsapFreeLsaHeap( Entry );
  141. Status = STATUS_SUCCESS;
  142. break;
  143. }
  144. Entry = (PLSAP_POLICY_NOTIFICATION_ENTRY)Entry->List.Flink;
  145. }
  146. SafeReleaseResource( &LsaPolicyChangeNotificationLock );
  147. return( Status );
  148. }
  149. NTSTATUS
  150. LsaINotifyChangeNotification(
  151. IN POLICY_NOTIFICATION_INFORMATION_CLASS InfoClass
  152. )
  153. /*++
  154. Routine Description:
  155. This function processes a notification list by making the appropriate
  156. callback calls when a policy object has changed
  157. Arguments:
  158. InfoClass -- Policy information that has changed
  159. Return Value:
  160. STATUS_SUCCESS -- Success
  161. STATUS_UNSUCCESSFUL -- Failed to lock the list for access
  162. --*/
  163. {
  164. NTSTATUS Status = STATUS_SUCCESS;
  165. ASSERT( InfoClass <=
  166. sizeof( LsaPolicyChangeNotificationList ) / sizeof( LSAP_POLICY_NOTIFICATION_LIST ) );
  167. if ( LsaIRegisterNotification( LsapNotifyChangeNotificationThread,
  168. ( PVOID ) InfoClass,
  169. NOTIFIER_TYPE_IMMEDIATE,
  170. 0,
  171. NOTIFIER_FLAG_ONE_SHOT,
  172. 0,
  173. 0 ) == NULL ) {
  174. Status = STATUS_INSUFFICIENT_RESOURCES;
  175. }
  176. return( Status );
  177. }
  178. DWORD
  179. WINAPI
  180. LsapNotifyChangeNotificationThread(
  181. LPVOID Parameter
  182. )
  183. /*++
  184. Routine Description:
  185. This function processes a notification list by making the appropriate
  186. callback calls when a policy object has changed
  187. Arguments:
  188. Parameter -- Policy information that has changed
  189. Return Value:
  190. STATUS_SUCCESS -- Success
  191. STATUS_UNSUCCESSFUL -- Failed to lock the list for access
  192. --*/
  193. {
  194. NTSTATUS Status = STATUS_SUCCESS;
  195. ULONG i;
  196. POLICY_NOTIFICATION_INFORMATION_CLASS InfoClass =
  197. ( POLICY_NOTIFICATION_INFORMATION_CLASS ) ( ( ULONG_PTR ) Parameter );
  198. PLSAP_POLICY_NOTIFICATION_ENTRY Entry;
  199. ASSERT( InfoClass <=
  200. sizeof( LsaPolicyChangeNotificationList ) / sizeof( LSAP_POLICY_NOTIFICATION_LIST ) );
  201. if ( !SafeAcquireResourceShared( &LsaPolicyChangeNotificationLock, TRUE ) ) {
  202. return STATUS_UNSUCCESSFUL;
  203. }
  204. Entry = (PLSAP_POLICY_NOTIFICATION_ENTRY)LsaPolicyChangeNotificationList[ InfoClass ].List.Flink;
  205. for ( i = 0; i < LsaPolicyChangeNotificationList[ InfoClass ].Callbacks; i++ ) {
  206. ASSERT( Entry->NotificationCallback || Entry->NotificationEvent );
  207. if ( Entry->NotificationCallback ) {
  208. (*Entry->NotificationCallback)( InfoClass );
  209. } else if ( Entry->NotificationEvent ) {
  210. if ( !Entry->HandleInvalid ) {
  211. Status = NtSetEvent( Entry->NotificationEvent, NULL );
  212. if ( Status == STATUS_INVALID_HANDLE ) {
  213. Entry->HandleInvalid = TRUE;
  214. }
  215. }
  216. } else {
  217. LsapDsDebugOut(( DEB_ERROR,
  218. "NULL callback found for info level %lu\n",
  219. InfoClass ));
  220. }
  221. Entry = (PLSAP_POLICY_NOTIFICATION_ENTRY)Entry->List.Flink;
  222. }
  223. SafeReleaseResource( &LsaPolicyChangeNotificationLock );
  224. return( Status );
  225. }
  226. NTSTATUS
  227. LsaIRegisterPolicyChangeNotificationCallback(
  228. IN pfLsaPolicyChangeNotificationCallback Callback,
  229. IN POLICY_NOTIFICATION_INFORMATION_CLASS MonitorInfoClass
  230. )
  231. /*++
  232. Routine Description:
  233. This function registers a callback with the Lsa server such that a change to the
  234. specified policy items results in the callback being called. These callbacks are
  235. informational only, such that a client must return instantly, not doing an Lsa
  236. calls in their callback.
  237. Multiple callbacks can be specified for the same policy information.
  238. Arguments:
  239. Callback -- Callback function pointer.
  240. MonitorInfoClass -- Policy information to watch for
  241. Return Value:
  242. STATUS_SUCCESS -- Success
  243. STATUS_INVALID_PARAMETER -- A bad callback pointer was specified
  244. STATUS_UNSUCCESSFUL -- Failed to lock the list for access
  245. --*/
  246. {
  247. NTSTATUS Status = STATUS_SUCCESS;
  248. if ( !Callback ) {
  249. return STATUS_INVALID_PARAMETER;
  250. }
  251. if ( !SafeAcquireResourceExclusive( &LsaPolicyChangeNotificationLock, TRUE ) ) {
  252. return STATUS_UNSUCCESSFUL;
  253. }
  254. ASSERT( MonitorInfoClass <=
  255. sizeof( LsaPolicyChangeNotificationList ) /
  256. sizeof( LSAP_POLICY_NOTIFICATION_LIST ) );
  257. Status = LsapNotifyAddCallbackToList(
  258. &LsaPolicyChangeNotificationList[ MonitorInfoClass ],
  259. Callback,
  260. NULL, 0, NULL );
  261. LsapDsDebugOut(( DEB_NOTIFY,
  262. "Insertion of callback 0x%lx for %lu returned 0x%lx\n",
  263. Callback,
  264. MonitorInfoClass,
  265. Status ));
  266. SafeReleaseResource( &LsaPolicyChangeNotificationLock );
  267. return( Status );
  268. }
  269. NTSTATUS
  270. LsaIUnregisterPolicyChangeNotificationCallback(
  271. IN pfLsaPolicyChangeNotificationCallback Callback,
  272. IN POLICY_NOTIFICATION_INFORMATION_CLASS MonitorInfoClass
  273. )
  274. /*++
  275. Routine Description:
  276. This function unregisters a callback from the Lsa server such that a change to the
  277. specified policy items do not result in a call to the client callback function.
  278. Arguments:
  279. Callback -- Callback function pointer to remove.
  280. MonitorInfoClass -- Policy information to remove the callback for
  281. Return Value:
  282. STATUS_SUCCESS -- Success
  283. STATUS_INVALID_PARAMETER -- A bad callback pointer was specified
  284. STATUS_UNSUCCESSFUL -- Failed to lock the list for access
  285. --*/
  286. {
  287. NTSTATUS Status = STATUS_SUCCESS;
  288. if ( !Callback ) {
  289. return STATUS_INVALID_PARAMETER;
  290. }
  291. if ( !SafeAcquireResourceExclusive( &LsaPolicyChangeNotificationLock, TRUE ) ) {
  292. return STATUS_UNSUCCESSFUL;
  293. }
  294. Status = LsapNotifyRemoveCallbackFromList(
  295. &LsaPolicyChangeNotificationList[ MonitorInfoClass ],
  296. Callback,
  297. 0, NULL );
  298. LsapDsDebugOut(( DEB_NOTIFY,
  299. "Removal of callback 0x%lx for %lu returned 0x%lx\n",
  300. Callback,
  301. MonitorInfoClass,
  302. Status ));
  303. SafeReleaseResource( &LsaPolicyChangeNotificationLock );
  304. return( Status );
  305. }
  306. NTSTATUS
  307. LsaIUnregisterAllPolicyChangeNotificationCallback(
  308. IN pfLsaPolicyChangeNotificationCallback Callback
  309. )
  310. /*++
  311. Routine Description:
  312. This function unregisters the specified callback function from all associated policy.
  313. This function is the equivalent of calling LsaIUnregisterPolicyChangeNotificationCallback
  314. for each InfoClass that was being watched.
  315. Arguments:
  316. Callback -- Callback function pointer to remove.
  317. Return Value:
  318. STATUS_SUCCESS -- Success
  319. STATUS_INVALID_PARAMETER -- A bad callback pointer was specified
  320. STATUS_UNSUCCESSFUL -- Failed to lock the list for access
  321. STATUS_NOT_FOUND -- No matching entries were found
  322. --*/
  323. {
  324. NTSTATUS Status = STATUS_SUCCESS;
  325. ULONG i, Removed = 0;
  326. if ( !Callback ) {
  327. return STATUS_INVALID_PARAMETER;
  328. }
  329. if ( !SafeAcquireResourceExclusive( &LsaPolicyChangeNotificationLock, TRUE ) ) {
  330. return STATUS_UNSUCCESSFUL;
  331. }
  332. Removed = 0;
  333. for ( i = 0;
  334. i < sizeof( LsaPolicyChangeNotificationList ) /
  335. sizeof( LSAP_POLICY_NOTIFICATION_LIST ) && NT_SUCCESS( Status );
  336. i++ ) {
  337. Status = LsapNotifyRemoveCallbackFromList(
  338. &LsaPolicyChangeNotificationList[ i ],
  339. Callback,
  340. 0, NULL );
  341. LsapDsDebugOut(( DEB_NOTIFY,
  342. "Removal of callback 0x%lx for %lu returned 0x%lx\n",
  343. Callback,
  344. i,
  345. Status ));
  346. if ( Status == STATUS_NOT_FOUND ) {
  347. Status = STATUS_SUCCESS;
  348. } else if ( Status == STATUS_SUCCESS ) {
  349. Removed++;
  350. }
  351. }
  352. SafeReleaseResource( &LsaPolicyChangeNotificationLock );
  353. //
  354. // Make sure we removed at least one
  355. //
  356. if ( NT_SUCCESS( Status ) ) {
  357. if ( Removed == 0 ) {
  358. Status = STATUS_NOT_FOUND;
  359. }
  360. }
  361. return( Status );
  362. }
  363. NTSTATUS
  364. LsapNotifyProcessNotificationEvent(
  365. IN POLICY_NOTIFICATION_INFORMATION_CLASS InformationClass,
  366. IN HANDLE NotificationEvent,
  367. IN ULONG OwnerProcess,
  368. IN HANDLE OwnerEventHandle,
  369. IN BOOLEAN Register
  370. )
  371. /*++
  372. Routine Description:
  373. This function registers / unregisters the specified Notification event handle for the
  374. specified information class
  375. Arguments:
  376. InformationClass -- Information class to add/remove the notification for
  377. NotificationEvent -- Event handle to register/deregister
  378. Register -- If TRUE, the event is being registered. If FALSE, it is unregistered
  379. Return Value:
  380. STATUS_SUCCESS -- Success
  381. STATUS_INVALID_HANDLE -- A bad event handle was specified
  382. STATUS_ACCESS_DENIED -- The opened policy handle does not have the requried permissions
  383. STATUS_INSUFFICIENT_RESOURCES -- A memory allocation failed
  384. STATUS_INVALID_INFO_CLASS -- An invalid information class was provided.
  385. --*/
  386. {
  387. NTSTATUS Status = STATUS_SUCCESS;
  388. LSAP_DB_OBJECT_INFORMATION ObjectInformation;
  389. POBJECT_TYPE_INFORMATION ObjTypeInfo = NULL;
  390. ULONG Length = 0, ReturnLength = 0;
  391. UNICODE_STRING EventString;
  392. LSAPR_HANDLE PolicyHandle = NULL;
  393. OBJECT_ATTRIBUTES ObjectAttributes;
  394. //
  395. // Make sure we are given a valid info class
  396. //
  397. if ( InformationClass < PolicyNotifyAuditEventsInformation ||
  398. InformationClass > PolicyNotifyMachineAccountPasswordInformation ) {
  399. return( STATUS_INVALID_INFO_CLASS );
  400. }
  401. //
  402. // Make sure the caller has the proper privileges.
  403. //
  404. // We're already impersonating our caller so LsapDbOpenPolicy doesn't need to.
  405. //
  406. InitializeObjectAttributes(
  407. &ObjectAttributes,
  408. NULL,
  409. 0L,
  410. NULL,
  411. NULL );
  412. Status = LsapDbOpenPolicy(
  413. NULL,
  414. (PLSAPR_OBJECT_ATTRIBUTES) &ObjectAttributes,
  415. POLICY_NOTIFICATION,
  416. LSAP_DB_USE_LPC_IMPERSONATE,
  417. &PolicyHandle,
  418. FALSE ); // Not a trusted client
  419. if ( NT_SUCCESS( Status ) && Register ) {
  420. if ( NotificationEvent == NULL ||
  421. NotificationEvent == INVALID_HANDLE_VALUE ) {
  422. Status = STATUS_INVALID_HANDLE;
  423. }
  424. }
  425. if ( NT_SUCCESS( Status ) && Register ) {
  426. //
  427. // Verify that the handle is one for an Event
  428. //
  429. Status = NtQueryObject( NotificationEvent,
  430. ObjectTypeInformation,
  431. ObjTypeInfo,
  432. Length,
  433. &ReturnLength );
  434. if ( Status == STATUS_INFO_LENGTH_MISMATCH ) {
  435. ObjTypeInfo = LsapAllocateLsaHeap( ReturnLength );
  436. if ( ObjTypeInfo == NULL ) {
  437. Status = STATUS_INSUFFICIENT_RESOURCES;
  438. } else {
  439. Length = ReturnLength;
  440. Status = NtQueryObject( NotificationEvent,
  441. ObjectTypeInformation,
  442. ObjTypeInfo,
  443. Length,
  444. &ReturnLength );
  445. if ( NT_SUCCESS( Status ) ) {
  446. //
  447. // See if it's actually an event
  448. //
  449. RtlInitUnicodeString( &EventString, L"Event" );
  450. if ( !RtlEqualUnicodeString( &EventString, &ObjTypeInfo->TypeName, FALSE ) ) {
  451. Status = STATUS_INVALID_HANDLE;
  452. }
  453. }
  454. LsapFreeLsaHeap( ObjTypeInfo );
  455. }
  456. } else if ( Status == STATUS_SUCCESS ) {
  457. LsapDsDebugOut(( DEB_ERROR, "NtQueryObject returned success on a NULL buffer\n" ));
  458. Status = STATUS_UNSUCCESSFUL;
  459. }
  460. }
  461. //
  462. // Now, add or remove the information from the list
  463. //
  464. if ( NT_SUCCESS( Status ) ) {
  465. if ( Register ) {
  466. Status = LsapNotifyAddCallbackToList(
  467. &LsaPolicyChangeNotificationList[ InformationClass ],
  468. NULL,
  469. NotificationEvent,
  470. OwnerProcess,
  471. OwnerEventHandle );
  472. } else {
  473. Status = LsapNotifyRemoveCallbackFromList(
  474. &LsaPolicyChangeNotificationList[ InformationClass ],
  475. NULL,
  476. OwnerProcess,
  477. OwnerEventHandle );
  478. }
  479. }
  480. if ( PolicyHandle != NULL ) {
  481. LsapCloseHandle( &PolicyHandle, Status );
  482. }
  483. return( Status );
  484. }