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.

1231 lines
30 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. svcshare.c
  5. Abstract:
  6. This module contains support routines for the server service.
  7. Author:
  8. David Treadwell (davidtr) 13-Feb-1991
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #include "svcsupp.tmh"
  13. #pragma hdrstop
  14. BOOLEAN
  15. FilterTransportName (
  16. IN PVOID Context,
  17. IN PVOID Block
  18. );
  19. #ifdef ALLOC_PRAGMA
  20. #pragma alloc_text( PAGE, SrvCopyUnicodeStringToBuffer )
  21. #pragma alloc_text( PAGE, SrvDeleteOrderedList )
  22. #pragma alloc_text( PAGE, SrvEnumApiHandler )
  23. #pragma alloc_text( PAGE, SrvFindEntryInOrderedList )
  24. #pragma alloc_text( PAGE, SrvFindNextEntryInOrderedList )
  25. #pragma alloc_text( PAGE, SrvFindUserOnConnection )
  26. #pragma alloc_text( PAGE, SrvGetResumeHandle )
  27. #pragma alloc_text( PAGE, SrvInitializeOrderedList )
  28. #pragma alloc_text( PAGE, SrvInsertEntryOrderedList )
  29. #pragma alloc_text( PAGE, SrvRemoveEntryOrderedList )
  30. #pragma alloc_text( PAGE, SrvSendDatagram )
  31. #pragma alloc_text( PAGE, FilterTransportName )
  32. #pragma alloc_text( PAGE, SrvLengthOfStringInApiBuffer )
  33. #pragma alloc_text( PAGE, SrvInhibitIdlePowerDown )
  34. #pragma alloc_text( PAGE, SrvAllowIdlePowerDown )
  35. #endif
  36. VOID
  37. SrvCopyUnicodeStringToBuffer (
  38. IN PUNICODE_STRING String,
  39. IN PCHAR FixedStructure,
  40. IN OUT LPWSTR *EndOfVariableData,
  41. OUT LPWSTR *VariableDataPointer
  42. )
  43. /*++
  44. Routine Description:
  45. This routine puts a single variable-length Unicode string into a
  46. buffer. The string data is converted to ANSI as it is copied. The
  47. string is not written if it would overwrite the last fixed structure
  48. in the buffer.
  49. Arguments:
  50. String - a pointer to the string to copy into the buffer. If String
  51. is null (Length == 0 || Buffer == NULL) then a pointer to a
  52. zero terminator is inserted.
  53. FixedStructure - a pointer to the end of the last fixed
  54. structure in the buffer.
  55. EndOfVariableData - the last position on the buffer that variable
  56. data for this structure can occupy.
  57. VariableDataPointer - a pointer to the place in the buffer where
  58. a pointer to the variable data should be written.
  59. Return Value:
  60. None.
  61. --*/
  62. {
  63. ULONG length;
  64. ULONG i;
  65. PWCH src;
  66. LPWSTR dest;
  67. PAGED_CODE( );
  68. //
  69. // Determine where in the buffer the string will go, allowing for a
  70. // zero-terminator.
  71. //
  72. if ( String->Buffer != NULL ) {
  73. length = String->Length >> 1;
  74. *EndOfVariableData -= (length + 1);
  75. } else {
  76. length = 0;
  77. *EndOfVariableData -= 1;
  78. }
  79. //
  80. // Will the string fit? If no, just set the pointer to NULL.
  81. //
  82. if ( (ULONG_PTR)*EndOfVariableData >= (ULONG_PTR)FixedStructure ) {
  83. //
  84. // It fits. Set up the pointer to the place in the buffer where
  85. // the string will go.
  86. //
  87. *VariableDataPointer = *EndOfVariableData;
  88. //
  89. // Copy the string to the buffer if it is not null.
  90. //
  91. dest = *EndOfVariableData;
  92. for ( i = 0, src = String->Buffer; i < length; i++ ) {
  93. *dest++ = (TCHAR)*src++;
  94. }
  95. //
  96. // Set the zero terminator.
  97. //
  98. *dest = (TCHAR)(L'\0');
  99. } else {
  100. //
  101. // It doesn't fit. Set the offset to NULL.
  102. //
  103. *VariableDataPointer = NULL;
  104. }
  105. return;
  106. } // SrvCopyUnicodeStringToBuffer
  107. VOID
  108. SrvDeleteOrderedList (
  109. IN PORDERED_LIST_HEAD ListHead
  110. )
  111. /*++
  112. Routine Description:
  113. "Deinitializes" or deletes an ordered list head.
  114. Arguments:
  115. ListHead - a pointer to the list head to delete.
  116. Return Value:
  117. None.
  118. --*/
  119. {
  120. PAGED_CODE( );
  121. if ( ListHead->Initialized ) {
  122. ASSERT( IsListEmpty( &ListHead->ListHead ) );
  123. //
  124. // Indicate that the ordered list has been "deleted".
  125. //
  126. ListHead->Initialized = FALSE;
  127. }
  128. return;
  129. } // SrvDeleteOrderedList
  130. NTSTATUS
  131. SrvEnumApiHandler (
  132. IN PSERVER_REQUEST_PACKET Srp,
  133. IN PVOID OutputBuffer,
  134. IN ULONG BufferLength,
  135. IN PORDERED_LIST_HEAD ListHead,
  136. IN PENUM_FILTER_ROUTINE FilterRoutine,
  137. IN PENUM_SIZE_ROUTINE SizeRoutine,
  138. IN PENUM_FILL_ROUTINE FillRoutine
  139. )
  140. /*++
  141. Routine Description:
  142. All Enum and GetInfo APIs are handled by this routine in the server
  143. FSD. It takes the ResumeHandle in the SRP to find the first
  144. appropriate block, then calls the passed-in filter routine to check
  145. if the block should be filled in. If it should, we call the filter
  146. routine, then try to get another block. This continues until tyhe
  147. entire list has been walked.
  148. Arguments:
  149. Srp - a pointer to the SRP for the operation.
  150. OutputBuffer - the buffer in which to fill output information.
  151. BufferLength - the length of the buffer.
  152. ListHead - the head of the ordered list to walk.
  153. FilterRoutine - a pointer to a function that will check a block
  154. against information in the SRP to determine whether the
  155. information in the block should be placed in the output
  156. buffer.
  157. SizeRoutine - a pointer to a function that will find the total size
  158. a single block will take up in the output buffer. This routine
  159. is used to check whether we should bother to call the fill
  160. routine.
  161. FillRoutine - a pointer to a function that will fill in the output
  162. buffer with information from a block.
  163. Return Value:
  164. NTSTATUS - results of operation.
  165. --*/
  166. {
  167. PVOID block;
  168. PVOID lastBlockRead;
  169. ULONG totalEntries;
  170. ULONG entriesRead;
  171. ULONG bytesRequired;
  172. ULONG newResumeHandle;
  173. PCHAR fixedStructurePointer;
  174. PCHAR variableData;
  175. ULONG level;
  176. ULONG maxResumeHandle;
  177. BOOLEAN bufferOverflow = FALSE;
  178. PAGED_CODE( );
  179. //
  180. // Set up local variables.
  181. //
  182. fixedStructurePointer = OutputBuffer;
  183. variableData = fixedStructurePointer + BufferLength;
  184. variableData = (PCHAR)((ULONG_PTR)variableData & ~1);
  185. level = Srp->Level;
  186. lastBlockRead = NULL;
  187. entriesRead = 0;
  188. totalEntries = 0;
  189. bytesRequired = 0;
  190. newResumeHandle = 0;
  191. //
  192. // Grab the current resume handle in the list we're
  193. // enumerating. This allows us to return only blocks that existed
  194. // when the enumeration started, thereby avoiding problems with
  195. // blocks created after the enumeration distorting the data.
  196. //
  197. maxResumeHandle = ListHead->CurrentResumeHandle;
  198. //
  199. // Get blocks from the global list by using the ordered list
  200. // routines. We pass resume handle +1 to get the next block after
  201. // the last one returned. If the passed-in resume handle is 0, this
  202. // will return the first valid block in the list.
  203. //
  204. block = SrvFindEntryInOrderedList(
  205. ListHead,
  206. NULL,
  207. NULL,
  208. Srp->Parameters.Get.ResumeHandle + 1,
  209. FALSE,
  210. NULL
  211. );
  212. while ( block != NULL &&
  213. SrvGetResumeHandle( ListHead, block ) < maxResumeHandle ) {
  214. ULONG blockSize;
  215. //
  216. // Call the filter routine to determine whether we should
  217. // return this block.
  218. //
  219. if ( FilterRoutine( Srp, block ) ) {
  220. blockSize = SizeRoutine( Srp, block );
  221. totalEntries++;
  222. bytesRequired += blockSize;
  223. //
  224. // If all the information in the block will fit in the
  225. // output buffer, write it. Otherwise, indicate that there
  226. // was an overflow. As soon as an entry doesn't fit, stop
  227. // putting them in the buffer. This ensures that the resume
  228. // mechanism will work--retuning partial entries would make
  229. // it nearly impossible to use the resumability of the APIs,
  230. // since the caller would have to resume from an imcomplete
  231. // entry.
  232. //
  233. if ( (ULONG_PTR)fixedStructurePointer + blockSize <=
  234. (ULONG_PTR)variableData && !bufferOverflow ) {
  235. FillRoutine(
  236. Srp,
  237. block,
  238. (PVOID *)&fixedStructurePointer,
  239. (LPWSTR *)&variableData
  240. );
  241. entriesRead++;
  242. lastBlockRead = block;
  243. newResumeHandle = SrvGetResumeHandle( ListHead, lastBlockRead );
  244. } else {
  245. bufferOverflow = TRUE;
  246. }
  247. }
  248. //
  249. // Get the next block in the list. This routine will dereference
  250. // the block we have been looking at and get a new block if a valid
  251. // one exists.
  252. //
  253. block = SrvFindNextEntryInOrderedList( ListHead, block );
  254. }
  255. //
  256. // Dereference this last one.
  257. //
  258. if ( block != NULL ) {
  259. ListHead->DereferenceRoutine( block );
  260. }
  261. //
  262. // Set the information to pass back to the server service.
  263. //
  264. Srp->Parameters.Get.EntriesRead = entriesRead;
  265. Srp->Parameters.Get.TotalEntries = totalEntries;
  266. Srp->Parameters.Get.TotalBytesNeeded = bytesRequired;
  267. //
  268. // If we found at least one block, return the resume handle for it.
  269. // If we didn't find any blocks, don't modify the resume handle.
  270. //
  271. if ( lastBlockRead != NULL ) {
  272. Srp->Parameters.Get.ResumeHandle = newResumeHandle;
  273. }
  274. //
  275. // Return appropriate status.
  276. //
  277. if ( entriesRead == 0 && totalEntries > 0 ) {
  278. //
  279. // Not even a single entry fit.
  280. //
  281. Srp->ErrorCode = NERR_BufTooSmall;
  282. return STATUS_SUCCESS;
  283. } else if ( bufferOverflow ) {
  284. //
  285. // At least one entry fit, but not all of them.
  286. //
  287. Srp->ErrorCode = ERROR_MORE_DATA;
  288. return STATUS_SUCCESS;
  289. } else {
  290. //
  291. // All entries fit.
  292. //
  293. Srp->ErrorCode = NO_ERROR;
  294. return STATUS_SUCCESS;
  295. }
  296. } // SrvEnumApiHandler
  297. PVOID
  298. SrvFindEntryInOrderedList (
  299. IN PORDERED_LIST_HEAD ListHead,
  300. IN PFILTER_ROUTINE FilterRoutine OPTIONAL,
  301. IN PVOID Context OPTIONAL,
  302. IN ULONG ResumeHandle,
  303. IN BOOLEAN ExactHandleMatch,
  304. IN PLIST_ENTRY StartLocation OPTIONAL
  305. )
  306. /*++
  307. Routine Description:
  308. This routine uses a filter routine or resume handle to find an entry
  309. in an ordered list. It walks the list, looking for a block with a
  310. resume handle less than or equal to the specified resume handle, or
  311. a block that passes the filter routine's tests. If a matching
  312. handle or passing block is found, the block is referenced and a
  313. pointer to it is returned. If ExactHandleMatch is FALSE and there
  314. is no exact match of the handle, then the first block with a resume
  315. handle greater than the one specified is referenced and returned.
  316. Arguments:
  317. ListHead - a pointer to the list head to search.
  318. FilterRoutine - a routine that will check whether a block is valid
  319. for the purposes of the calling routine.
  320. Context - a pointer to pass to the filter routine.
  321. ResumeHandle - the resume handle to look for. If a filter routine
  322. is specified, this parameter should be -1.
  323. ExactHandleMatch - if TRUE, only an exact match is returned. If there
  324. is no exact match, return NULL. If a filter routine is specified
  325. this should be FALSE.
  326. StartLocation - if specified, start looking at this location in
  327. the list. This is used by SrvFindNextEntryInOrderedList to
  328. speed up finding a valid block.
  329. Return Value:
  330. PVOID - NULL if no block matched or if the handle is beyond the end of
  331. the list. A pointer to a block if a valid block is found. The
  332. block is referenced.
  333. --*/
  334. {
  335. PLIST_ENTRY listEntry;
  336. PVOID block;
  337. PAGED_CODE( );
  338. //
  339. // Acquire the lock that protects the ordered list.
  340. //
  341. ACQUIRE_LOCK( ListHead->Lock );
  342. //
  343. // Find the starting location for the search. If a start was
  344. // specified, start there; otherwise, start at the beginning of the
  345. // list.
  346. //
  347. if ( ARGUMENT_PRESENT( StartLocation ) ) {
  348. listEntry = StartLocation;
  349. } else {
  350. listEntry = ListHead->ListHead.Flink;
  351. }
  352. //
  353. // Walk the list of blocks until we find one with a resume handle
  354. // greater than or equal to the specified resume handle.
  355. //
  356. for ( ; listEntry != &ListHead->ListHead; listEntry = listEntry->Flink ) {
  357. ULONG currentResumeHandle;
  358. currentResumeHandle = ((PORDERED_LIST_ENTRY)listEntry)->ResumeHandle;
  359. //
  360. // Get a pointer to the actual block.
  361. //
  362. block = (PCHAR)listEntry - ListHead->ListEntryOffset;
  363. //
  364. // Determine whether we've reached the specified handle, or
  365. // whether the block passes the filter routine's tests.
  366. //
  367. if ( currentResumeHandle >= ResumeHandle ||
  368. ( ARGUMENT_PRESENT( FilterRoutine ) &&
  369. FilterRoutine( Context, block ) ) ) {
  370. if ( ExactHandleMatch && currentResumeHandle != ResumeHandle ) {
  371. //
  372. // We have passed the specified resume handle without
  373. // finding an exact match. Return NULL, indicating that
  374. // no exact match exists.
  375. //
  376. RELEASE_LOCK( ListHead->Lock );
  377. return NULL;
  378. }
  379. //
  380. // Check the state of the block and if it is active,
  381. // reference it. This must be done as an atomic operation
  382. // order to prevent the block from being deleted.
  383. //
  384. if ( ListHead->ReferenceRoutine( block ) ) {
  385. //
  386. // Release the list lock and return a pointer to the
  387. // block to the caller.
  388. //
  389. RELEASE_LOCK( ListHead->Lock );
  390. return block;
  391. }
  392. }
  393. } // walk list
  394. //
  395. // If we are here, it means that we walked the entire list without
  396. // finding a valid match. Release the list lock and return NULL.
  397. //
  398. RELEASE_LOCK( ListHead->Lock );
  399. return NULL;
  400. } // SrvFindEntryInOrderedList
  401. PVOID
  402. SrvFindNextEntryInOrderedList (
  403. IN PORDERED_LIST_HEAD ListHead,
  404. IN PVOID Block
  405. )
  406. /*++
  407. Routine Description:
  408. This routine finds the next valid block after the one passed in.
  409. It calls SrvFindEntryInOrderedList to do most of the work. It
  410. also handles dereferencing the passed-in block and referencing the
  411. returned block. The passed-in block is dereferenced regardless
  412. of whether a block is returned, so calling routines must be careful
  413. to obtain all the information they need from the block before
  414. calling this routine.
  415. Arguments:
  416. ListHead - a pointer to the list head to search.
  417. Block - a pointer to the block after which we should look for
  418. the next block.
  419. Return Value:
  420. PVOID - NULL if no block matched or if the handle is beyond the end of
  421. the list. A pointer to a block if a valid block is found.
  422. --*/
  423. {
  424. PVOID returnBlock;
  425. PORDERED_LIST_ENTRY listEntry;
  426. PAGED_CODE( );
  427. //
  428. // Find the ordered list entry in the block. We need this to pass
  429. // the start location and resume handle to
  430. // SrvFindEntryInOrderedList.
  431. //
  432. listEntry =
  433. (PORDERED_LIST_ENTRY)( (PCHAR)Block + ListHead->ListEntryOffset );
  434. //
  435. // Call SrvFindEntryInOrderedList with a start location. This will
  436. // find the block to return, if any.
  437. //
  438. // This adds one to the resume handle because we want the *next*
  439. // block, not this one, to be returned.
  440. //
  441. returnBlock = SrvFindEntryInOrderedList(
  442. ListHead,
  443. NULL,
  444. NULL,
  445. listEntry->ResumeHandle + 1,
  446. FALSE,
  447. &listEntry->ListEntry
  448. );
  449. //
  450. // Dereference the passed-in block.
  451. //
  452. ListHead->DereferenceRoutine( Block );
  453. //
  454. // Return what we got from SrvFindEntryInOrderedList.
  455. //
  456. return returnBlock;
  457. } // SrvFindNextEntryInOrderedList
  458. PSESSION
  459. SrvFindUserOnConnection (
  460. IN PCONNECTION Connection
  461. )
  462. /*++
  463. Routine Description:
  464. Finds a "legitimate" user on a virtual circuit. This routine is
  465. an attempt to find a good username to return even though there
  466. may be multiple users on a VC. Some of the APIs assume that there
  467. will be one user per VC, and this is an attempt to support that
  468. bahavior.
  469. The following rules are used:
  470. 0 users--return NULL.
  471. 1 user--return a pointer to that session block.
  472. 2 users--if one matches the computer name, return the other. This
  473. is because RIPL sessions have a session name matching the
  474. client name, and this is probably not a useful user. If both
  475. usernames differ from the computer name, return NULL.
  476. 3 or more users--return NULL.
  477. *** THIS ROUTINE MUST BE CALLED WITH THE CONNECTION LOCK HELD. It
  478. remains held on exit.
  479. Arguments:
  480. Connection - a pointer to the connection block to search for a user.
  481. Return Value:
  482. NULL or a pointer to a session.
  483. --*/
  484. {
  485. PSESSION matchingSession = NULL;
  486. PSESSION nonMatchingSession = NULL;
  487. USHORT i;
  488. PPAGED_CONNECTION pagedConnection = Connection->PagedConnection;
  489. PAGED_CODE( );
  490. //
  491. // Walk the connection's session table looking for valid sessions.
  492. //
  493. for ( i = 0; i < pagedConnection->SessionTable.TableSize; i++ ) {
  494. PSESSION session;
  495. session = pagedConnection->SessionTable.Table[i].Owner;
  496. //
  497. // Determine whether this is a valid session.
  498. //
  499. if ( session != NULL && GET_BLOCK_STATE(session) == BlockStateActive ) {
  500. //
  501. // It is a valid session. Determine whether the name matches
  502. // the connection's client name.
  503. //
  504. UNICODE_STRING computerName, userName;
  505. computerName.Buffer = Connection->ClientMachineName;
  506. computerName.Length =
  507. (USHORT)( Connection->ClientMachineNameString.Length -
  508. sizeof(WCHAR) * 2 );
  509. SrvGetUserAndDomainName( session, &userName, NULL );
  510. if( userName.Buffer && userName.Length != 0 ) {
  511. if ( RtlCompareUnicodeString(
  512. &computerName,
  513. &userName,
  514. TRUE ) == 0 ) {
  515. //
  516. // The user name and machine name are the same.
  517. //
  518. matchingSession = session;
  519. } else {
  520. //
  521. // If we already found another user name that doesn't match
  522. // the client computer name, we're hosed. Return NULL.
  523. //
  524. if ( nonMatchingSession != NULL ) {
  525. SrvReleaseUserAndDomainName( session, &userName, NULL );
  526. return NULL;
  527. }
  528. nonMatchingSession = session;
  529. } // does session user name match computer name?
  530. SrvReleaseUserAndDomainName( session, &userName, NULL );
  531. }
  532. } // valid session?
  533. } // walk session table
  534. //
  535. // If only one non-matching name was found, we got here, so return
  536. // that session.
  537. //
  538. if ( nonMatchingSession != NULL ) {
  539. return nonMatchingSession;
  540. }
  541. //
  542. // If a matching session was found return it, or return NULL if
  543. // no sessions matched.
  544. //
  545. return matchingSession;
  546. } // SrvFindUserOnConnection
  547. ULONG
  548. SrvGetResumeHandle (
  549. IN PORDERED_LIST_HEAD ListHead,
  550. IN PVOID Block
  551. )
  552. {
  553. PORDERED_LIST_ENTRY listEntry;
  554. PAGED_CODE( );
  555. // !!! make this a macro?
  556. listEntry =
  557. (PORDERED_LIST_ENTRY)( (PCHAR)Block + ListHead->ListEntryOffset );
  558. return listEntry->ResumeHandle;
  559. } // SrvGetResumeHandle
  560. VOID
  561. SrvInitializeOrderedList (
  562. IN PORDERED_LIST_HEAD ListHead,
  563. IN ULONG ListEntryOffset,
  564. IN PREFERENCE_ROUTINE ReferenceRoutine,
  565. IN PDEREFERENCE_ROUTINE DereferenceRoutine,
  566. IN PSRV_LOCK Lock
  567. )
  568. /*++
  569. Routine Description:
  570. This routine initializes an ordered list. It initializes the list
  571. head and lock and sets up other header fields from the information
  572. passed in.
  573. Arguments:
  574. ListHead - a pointer to the list head to initialize.
  575. ListEntryOffset - the offset into a data block in the list to the
  576. ORDERED_LIST_ENTRY field. This is used to find the start of
  577. the block from the list entry field.
  578. ReferenceRoutine - a pointer to the routine to call to reference
  579. a data block stored in the list. This is done to prevent the
  580. data block from going away between when we find it and when
  581. higher-level routines start using it.
  582. DereferenceRoutine - a pointer to the routine to call to dereference
  583. a data block stored in the list.
  584. Lock - a pointer to a lock to use for synchronization.
  585. Return Value:
  586. None.
  587. --*/
  588. {
  589. PAGED_CODE( );
  590. ASSERT( !ListHead->Initialized );
  591. //
  592. // Initialize the head of the doubly linked list.
  593. //
  594. InitializeListHead( &ListHead->ListHead );
  595. //
  596. // Save the address of the list lock.
  597. //
  598. ASSERT( ARGUMENT_PRESENT(Lock) );
  599. ListHead->Lock = Lock;
  600. //
  601. // Initialize other fields in the header.
  602. //
  603. ListHead->CurrentResumeHandle = 1;
  604. ListHead->ListEntryOffset = ListEntryOffset;
  605. ListHead->ReferenceRoutine = ReferenceRoutine,
  606. ListHead->DereferenceRoutine = DereferenceRoutine;
  607. ListHead->Initialized = TRUE;
  608. return;
  609. } // SrvInitializeOrderedList
  610. VOID
  611. SrvInsertEntryOrderedList (
  612. IN PORDERED_LIST_HEAD ListHead,
  613. IN PVOID Block
  614. )
  615. /*++
  616. Routine Description:
  617. This routine inserts an entry in an ordered list. The entry is
  618. placed on the doubly linked list and the resume handle is set.
  619. *** It is the responsibility of that calling routine to ensure that
  620. the block does not go away while this routine executes.
  621. Arguments:
  622. ListHead - a pointer to the list head on which to put the block.
  623. Block - a pointer to the data block to place on the list.
  624. Return Value:
  625. None.
  626. --*/
  627. {
  628. PORDERED_LIST_ENTRY listEntry;
  629. PAGED_CODE( );
  630. //
  631. // Determine where the list entry field is.
  632. //
  633. listEntry = (PORDERED_LIST_ENTRY)
  634. ( (PCHAR)Block + ListHead->ListEntryOffset );
  635. //
  636. // Acquire the lock that protects the ordered list.
  637. //
  638. ACQUIRE_LOCK( ListHead->Lock );
  639. //
  640. // Insert the entry in the doubly linked list.
  641. //
  642. SrvInsertTailList( &ListHead->ListHead, &listEntry->ListEntry );
  643. //
  644. // Set up the resume handle in the block and update the current
  645. // handle in the header.
  646. //
  647. listEntry->ResumeHandle = ListHead->CurrentResumeHandle;
  648. ListHead->CurrentResumeHandle++;
  649. //
  650. // Release the lock and return.
  651. //
  652. RELEASE_LOCK( ListHead->Lock );
  653. return;
  654. } // SrvInsertEntryOrderedList
  655. VOID
  656. SrvRemoveEntryOrderedList (
  657. IN PORDERED_LIST_HEAD ListHead,
  658. IN PVOID Block
  659. )
  660. /*++
  661. Routine Description:
  662. This routine removes an entry from an ordered list.
  663. *** It is the responsibility of that calling routine to ensure that
  664. the block does not go away while this routine executes.
  665. Arguments:
  666. ListHead - a pointer to the list head on which to put the block.
  667. Block - a pointer to the data block to place on the list.
  668. Return Value:
  669. None.
  670. --*/
  671. {
  672. PORDERED_LIST_ENTRY listEntry;
  673. PAGED_CODE( );
  674. //
  675. // Determine where the list entry field is.
  676. //
  677. listEntry = (PORDERED_LIST_ENTRY)
  678. ( (PCHAR)Block + ListHead->ListEntryOffset );
  679. //
  680. // Acquire the lock that protects the ordered list.
  681. //
  682. ACQUIRE_LOCK( ListHead->Lock );
  683. //
  684. // Remove the entry from the doubly linked list.
  685. //
  686. SrvRemoveEntryList( &ListHead->ListHead, &listEntry->ListEntry );
  687. //
  688. // Release the lock and return.
  689. //
  690. RELEASE_LOCK( ListHead->Lock );
  691. return;
  692. } // SrvRemoveEntryOrderedList
  693. NTSTATUS
  694. SrvSendDatagram (
  695. IN PANSI_STRING Domain,
  696. IN PUNICODE_STRING Transport OPTIONAL,
  697. IN PVOID Buffer,
  698. IN ULONG BufferLength
  699. )
  700. /*++
  701. Routine Description:
  702. This routine sends a datagram to the specified domain.
  703. !!! Temporary--should go away when we have real 2nd-class mailslot
  704. support.
  705. Arguments:
  706. Domain - the name of the domain to send to. Note that the domain
  707. name must be padded with spaces and terminated with the
  708. appropriate signature byte (00 or 07) by the caller.
  709. Transport - the name of the transport to send to. If not present, then
  710. the datagram is sent on all transports.
  711. Buffer - the message to send.
  712. BufferLength - the length of the buffer,
  713. Return Value:
  714. NTSTATUS - results of operation.
  715. --*/
  716. {
  717. NTSTATUS status = STATUS_SUCCESS;
  718. ULONG connectionInformationSize;
  719. PTDI_CONNECTION_INFORMATION connectionInformation;
  720. PTA_NETBIOS_ADDRESS taNetbiosAddress;
  721. PENDPOINT endpoint;
  722. PAGED_CODE( );
  723. connectionInformationSize = sizeof(TDI_CONNECTION_INFORMATION) +
  724. sizeof(TA_NETBIOS_ADDRESS);
  725. connectionInformation = ALLOCATE_NONPAGED_POOL(
  726. connectionInformationSize,
  727. BlockTypeDataBuffer
  728. );
  729. if ( connectionInformation == NULL ) {
  730. return STATUS_INSUFF_SERVER_RESOURCES;
  731. }
  732. connectionInformation->UserDataLength = 0;
  733. connectionInformation->UserData = NULL;
  734. connectionInformation->OptionsLength = 0;
  735. connectionInformation->Options = NULL;
  736. connectionInformation->RemoteAddressLength = sizeof(TA_NETBIOS_ADDRESS);
  737. taNetbiosAddress = (PTA_NETBIOS_ADDRESS)(connectionInformation + 1);
  738. connectionInformation->RemoteAddress = taNetbiosAddress;
  739. taNetbiosAddress->TAAddressCount = 1;
  740. taNetbiosAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
  741. taNetbiosAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_NETBIOS);
  742. taNetbiosAddress->Address[0].Address[0].NetbiosNameType = 0;
  743. RtlCopyMemory(
  744. taNetbiosAddress->Address[0].Address[0].NetbiosName,
  745. Domain->Buffer,
  746. MIN( Domain->Length, COMPUTER_NAME_LENGTH + 1 )
  747. );
  748. endpoint = SrvFindEntryInOrderedList(
  749. &SrvEndpointList,
  750. FilterTransportName,
  751. Transport,
  752. (ULONG)-1,
  753. FALSE,
  754. NULL
  755. );
  756. while ( endpoint != NULL ) {
  757. if ( !endpoint->IsConnectionless ) {
  758. if( endpoint->IsNoNetBios ) {
  759. //
  760. // Make mailslot sends over this transport "always work"
  761. //
  762. status = STATUS_SUCCESS;
  763. } else {
  764. status = SrvIssueSendDatagramRequest(
  765. endpoint->FileObject,
  766. &endpoint->DeviceObject,
  767. connectionInformation,
  768. Buffer,
  769. BufferLength
  770. );
  771. }
  772. } else {
  773. //
  774. // Dereference the endpoint if this was targetted to a specific
  775. // transport, and return an error.
  776. //
  777. if (Transport != NULL) {
  778. DEALLOCATE_NONPAGED_POOL( connectionInformation );
  779. SrvDereferenceEndpoint( endpoint );
  780. return STATUS_REQUEST_NOT_ACCEPTED;
  781. }
  782. }
  783. if (Transport == NULL) {
  784. //
  785. // Find the next endpoint. This will dereference the current
  786. // endpoint.
  787. //
  788. endpoint = SrvFindNextEntryInOrderedList( &SrvEndpointList, endpoint );
  789. } else {
  790. //
  791. // This datagram was destined to a specific endpoint. Do not
  792. // look for the next endpoint.
  793. //
  794. SrvDereferenceEndpoint( endpoint );
  795. endpoint = NULL;
  796. }
  797. }
  798. DEALLOCATE_NONPAGED_POOL( connectionInformation );
  799. return status;
  800. } // SrvSendDatagram
  801. BOOLEAN
  802. FilterTransportName (
  803. IN PVOID Context,
  804. IN PVOID Block
  805. )
  806. {
  807. PENDPOINT endpoint = Block;
  808. PAGED_CODE( );
  809. if ( Context == NULL ) {
  810. return( TRUE );
  811. }
  812. return ( RtlEqualUnicodeString ( &endpoint->TransportName, (PUNICODE_STRING)Context, TRUE ) );
  813. }
  814. ULONG
  815. SrvLengthOfStringInApiBuffer (
  816. IN PUNICODE_STRING UnicodeString
  817. )
  818. {
  819. PAGED_CODE( );
  820. if ( UnicodeString == NULL ) {
  821. return 0;
  822. }
  823. return UnicodeString->Length + sizeof(UNICODE_NULL);
  824. } // SrvLengthOfStringInApiBuffer
  825. //
  826. // Ensure that the system will not go into a power-down idle standby mode
  827. //
  828. VOID
  829. SrvInhibitIdlePowerDown()
  830. {
  831. PAGED_CODE();
  832. if( SrvPoRegistrationState != NULL &&
  833. InterlockedIncrement( &SrvIdleCount ) == 1 ) {
  834. IF_DEBUG( PNP ) {
  835. KdPrint(( "SRV: Calling PoRegisterSystemState to inhibit idle standby\n" ));
  836. }
  837. PoRegisterSystemState( SrvPoRegistrationState, ES_SYSTEM_REQUIRED | ES_CONTINUOUS );
  838. }
  839. }
  840. //
  841. // Allow the system to go into a power-down idle standby mode
  842. //
  843. VOID
  844. SrvAllowIdlePowerDown()
  845. {
  846. PAGED_CODE();
  847. if( SrvPoRegistrationState != NULL &&
  848. InterlockedDecrement( &SrvIdleCount ) == 0 ) {
  849. IF_DEBUG( PNP ) {
  850. KdPrint(( "SRV: Calling PoRegisterSystemState to allow idle standby\n" ));
  851. }
  852. PoRegisterSystemState( SrvPoRegistrationState, ES_CONTINUOUS );
  853. }
  854. }