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.

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