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.

1169 lines
27 KiB

  1. /*++
  2. Copyright (c) 1991-1992 Microsoft Corporation
  3. Module Name:
  4. SsSubs.c
  5. Abstract:
  6. This module contains support routines for the NT server service.
  7. Author:
  8. David Treadwell (davidtr) 10-Jan-1991
  9. Revision History:
  10. --*/
  11. #include "srvsvcp.h"
  12. #include "ssreg.h"
  13. #include <lmerr.h>
  14. #include <lmsname.h>
  15. #include <netlibnt.h>
  16. #include <tstr.h>
  17. #include <ctype.h>
  18. #include <stdarg.h>
  19. #include <stdio.h>
  20. #include <ntddnfs.h>
  21. #define MRXSMB_DEVICE_NAME TEXT("\\Device\\LanmanRedirector")
  22. PSERVER_REQUEST_PACKET
  23. SsAllocateSrp (
  24. VOID
  25. )
  26. /*++
  27. Routine Description:
  28. This routine allocates a serer request packet so that an API can
  29. communicate with the kernel-mode server. Any general initialization
  30. in performed here.
  31. Arguments:
  32. None.
  33. Return Value:
  34. PSERVER_REQUEST_PACKET - a pointer to the allocated SRP.
  35. --*/
  36. {
  37. PSERVER_REQUEST_PACKET srp;
  38. srp = MIDL_user_allocate( sizeof(SERVER_REQUEST_PACKET) );
  39. if ( srp != NULL ) {
  40. RtlZeroMemory( srp, sizeof(SERVER_REQUEST_PACKET) );
  41. }
  42. return srp;
  43. } // SsAllocateSrp
  44. #if DBG
  45. VOID
  46. SsAssert(
  47. IN PVOID FailedAssertion,
  48. IN PVOID FileName,
  49. IN ULONG LineNumber
  50. )
  51. {
  52. BOOL ok;
  53. CHAR choice[16];
  54. DWORD bytes;
  55. DWORD error;
  56. SsPrintf( "\nAssertion failed: %s\n at line %ld of %s\n",
  57. FailedAssertion, LineNumber, FileName );
  58. do {
  59. HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
  60. SsPrintf( "Break or Ignore [bi]? " );
  61. if (hStdIn && (hStdIn != INVALID_HANDLE_VALUE))
  62. {
  63. bytes = sizeof(choice);
  64. ok = ReadFile(
  65. hStdIn,
  66. &choice,
  67. bytes,
  68. &bytes,
  69. NULL
  70. );
  71. }
  72. else
  73. {
  74. // default to "break"
  75. ok = TRUE;
  76. choice[0] = TEXT('B');
  77. }
  78. if ( ok ) {
  79. if ( toupper(choice[0]) == 'I' ) {
  80. break;
  81. }
  82. if ( toupper(choice[0]) == 'B' ) {
  83. DbgUserBreakPoint( );
  84. }
  85. } else {
  86. error = GetLastError( );
  87. }
  88. } while ( TRUE );
  89. return;
  90. } // SsAssert
  91. #endif
  92. VOID
  93. SsCloseServer (
  94. VOID
  95. )
  96. /*++
  97. Routine Description:
  98. This routine closes the server file system device, if it has been
  99. opened.
  100. Arguments:
  101. None.
  102. Return Value:
  103. None.
  104. --*/
  105. {
  106. //
  107. // Close the server device, if it has been opened.
  108. //
  109. if ( SsData.SsServerDeviceHandle != NULL ) {
  110. NtClose( SsData.SsServerDeviceHandle );
  111. SsData.SsServerDeviceHandle = NULL;
  112. }
  113. } // SsCloseServer
  114. VOID
  115. SsControlCHandler (
  116. IN ULONG CtrlType
  117. )
  118. /*++
  119. Routine Description:
  120. Captures and ignores a kill signal. Without this, any ^C pressed in
  121. the window that started the server service will result in this
  122. process being killed, and then the server can't function properly.
  123. Arguments:
  124. None.
  125. Return Value:
  126. None.
  127. --*/
  128. {
  129. CtrlType;
  130. return;
  131. } // SsControlCHandler
  132. VOID
  133. SsFreeSrp (
  134. IN PSERVER_REQUEST_PACKET Srp
  135. )
  136. /*++
  137. Routine Description:
  138. Frees an SRP allocated by SsAllocateSrp.
  139. Arguments:
  140. Srp - a pointer to the SRP to free.
  141. Return Value:
  142. None.
  143. --*/
  144. {
  145. MIDL_user_free( Srp );
  146. } // SsFreeSrp
  147. VOID
  148. SsLogEvent(
  149. IN DWORD MessageId,
  150. IN DWORD NumberOfSubStrings,
  151. IN LPWSTR *SubStrings,
  152. IN DWORD ErrorCode
  153. )
  154. {
  155. HANDLE logHandle;
  156. DWORD dataSize = 0;
  157. LPVOID rawData = NULL;
  158. USHORT eventType = EVENTLOG_ERROR_TYPE;
  159. logHandle = RegisterEventSource(
  160. NULL,
  161. SERVER_DISPLAY_NAME
  162. );
  163. if ( logHandle == NULL ) {
  164. SS_PRINT(( "SRVSVC: RegisterEventSource failed: %lu\n",
  165. GetLastError() ));
  166. return;
  167. }
  168. if ( ErrorCode != NERR_Success ) {
  169. //
  170. // An error code was specified.
  171. //
  172. dataSize = sizeof(ErrorCode);
  173. rawData = (LPVOID)&ErrorCode;
  174. }
  175. //
  176. // If the message is is only a warning, then set the event type as such.
  177. // This is doc'd in netevent.h.
  178. //
  179. if ((ULONG)(MessageId & 0xC0000000) == (ULONG) 0x80000000 ) {
  180. eventType = EVENTLOG_WARNING_TYPE;
  181. }
  182. //
  183. // Log the error.
  184. //
  185. if ( !ReportEventW(
  186. logHandle,
  187. eventType,
  188. 0, // event category
  189. MessageId,
  190. NULL, // user SID
  191. (WORD)NumberOfSubStrings,
  192. dataSize,
  193. SubStrings,
  194. rawData
  195. ) ) {
  196. SS_PRINT(( "SRVSVC: ReportEvent failed: %lu\n",
  197. GetLastError() ));
  198. }
  199. if ( !DeregisterEventSource( logHandle ) ) {
  200. SS_PRINT(( "SRVSVC: DeregisterEventSource failed: %lu\n",
  201. GetLastError() ));
  202. }
  203. return;
  204. } // SsLogEvent
  205. NET_API_STATUS
  206. SsOpenServer ()
  207. /*++
  208. Routine Description:
  209. This routine opens the server file system device, allowing the
  210. server service to send FS controls to it.
  211. Arguments:
  212. None.
  213. Return Value:
  214. NET_API_STATUS - results of operation.
  215. --*/
  216. {
  217. NTSTATUS status;
  218. UNICODE_STRING unicodeServerName;
  219. OBJECT_ATTRIBUTES objectAttributes;
  220. IO_STATUS_BLOCK ioStatusBlock;
  221. //
  222. // Open the server device.
  223. //
  224. RtlInitUnicodeString( &unicodeServerName, SERVER_DEVICE_NAME );
  225. InitializeObjectAttributes(
  226. &objectAttributes,
  227. &unicodeServerName,
  228. OBJ_CASE_INSENSITIVE,
  229. NULL,
  230. NULL
  231. );
  232. //
  233. // Opening the server with desired access = SYNCHRONIZE and open
  234. // options = FILE_SYNCHRONOUS_IO_NONALERT means that we don't have
  235. // to worry about waiting for the NtFsControlFile to complete--this
  236. // makes all IO system calls that use this handle synchronous.
  237. //
  238. status = NtOpenFile(
  239. &SsData.SsServerDeviceHandle,
  240. FILE_ALL_ACCESS & ~SYNCHRONIZE,
  241. &objectAttributes,
  242. &ioStatusBlock,
  243. 0,
  244. 0
  245. );
  246. if ( NT_SUCCESS(status) ) {
  247. status = ioStatusBlock.Status;
  248. }
  249. if ( !NT_SUCCESS(status) ) {
  250. IF_DEBUG(INITIALIZATION_ERRORS) {
  251. SS_PRINT(( "SsOpenServer: NtOpenFile (server device object) "
  252. "failed: %X\n", status ));
  253. }
  254. return NetpNtStatusToApiStatus( status );
  255. }
  256. //
  257. // We're now ready to talk to the server.
  258. //
  259. return NO_ERROR;
  260. } // SsOpenServer
  261. #if DBG
  262. VOID
  263. SsPrintf (
  264. char *Format,
  265. ...
  266. )
  267. {
  268. va_list arglist;
  269. char OutputBuffer[1024];
  270. ULONG length;
  271. HANDLE hStdOut;
  272. va_start( arglist, Format );
  273. vsprintf( OutputBuffer, Format, arglist );
  274. va_end( arglist );
  275. length = strlen( OutputBuffer );
  276. hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
  277. if (hStdOut && (hStdOut != INVALID_HANDLE_VALUE))
  278. {
  279. WriteFile(hStdOut, (LPVOID )OutputBuffer, length, &length, NULL );
  280. }
  281. } // SsPrintf
  282. #endif
  283. NET_API_STATUS
  284. SsServerFsControlGetInfo (
  285. IN ULONG ServerControlCode,
  286. IN PSERVER_REQUEST_PACKET Srp,
  287. IN OUT PVOID *OutputBuffer,
  288. IN ULONG PreferredMaximumLength
  289. )
  290. /*++
  291. Routine Description:
  292. This routine sends an SRP to the server for an API that retrieves
  293. information from the server and takes a PreferredMaximumLength
  294. parameter.
  295. Arguments:
  296. ServerControlCode - the FSCTL code for the operation.
  297. Srp - a pointer to the SRP for the operation.
  298. OutputBuffer - a pointer to receive a pointer to the buffer
  299. allocated by this routine to hold the output information.
  300. PreferredMaximumLength - the PreferredMaximumLength parameter.
  301. Return Value:
  302. NET_API_STATUS - results of operation.
  303. --*/
  304. {
  305. NET_API_STATUS status = STATUS_SUCCESS;
  306. ULONG resumeHandle = Srp->Parameters.Get.ResumeHandle;
  307. ULONG BufLen = min( INITIAL_BUFFER_SIZE, PreferredMaximumLength );
  308. ULONG i;
  309. *OutputBuffer = NULL;
  310. //
  311. // Normally, we should only go through this loop at most 2 times. But
  312. // if the amount of data the server needs to return is growing, then
  313. // we might be forced to run through it a couple of more times. '5'
  314. // is an arbitrary number just to ensure we don't get stuck.
  315. //
  316. for( i=0; i < 5; i++ ) {
  317. if( *OutputBuffer ) {
  318. MIDL_user_free( *OutputBuffer );
  319. }
  320. *OutputBuffer = MIDL_user_allocate( BufLen );
  321. if( *OutputBuffer == NULL ) {
  322. status = ERROR_NOT_ENOUGH_MEMORY;
  323. break;
  324. }
  325. //
  326. // Make the request of the server.
  327. //
  328. Srp->Parameters.Get.ResumeHandle = resumeHandle;
  329. status = SsServerFsControl(
  330. ServerControlCode,
  331. Srp,
  332. *OutputBuffer,
  333. BufLen
  334. );
  335. //
  336. // If we were successful, or we got an error other than our buffer
  337. // being too small, break out.
  338. //
  339. if ( status != ERROR_MORE_DATA && status != NERR_BufTooSmall ) {
  340. break;
  341. }
  342. //
  343. // We've been told that our buffer isn't big enough. But if we've hit
  344. // the caller's PreferredMaximumLength, break out.
  345. //
  346. if( BufLen >= PreferredMaximumLength ) {
  347. break;
  348. }
  349. //
  350. // Let's try again. EXTRA_ALLOCATION is here to cover the case where the
  351. // amount of space required grows between the previous FsControl call and
  352. // the next one.
  353. //
  354. BufLen = min( Srp->Parameters.Get.TotalBytesNeeded + EXTRA_ALLOCATION,
  355. PreferredMaximumLength );
  356. }
  357. if ( *OutputBuffer && Srp->Parameters.Get.EntriesRead == 0 ) {
  358. MIDL_user_free( *OutputBuffer );
  359. *OutputBuffer = NULL;
  360. }
  361. return status;
  362. } // SsServerFsControlGetInfo
  363. NET_API_STATUS
  364. SsServerFsControl (
  365. IN ULONG ServerControlCode,
  366. IN PSERVER_REQUEST_PACKET Srp OPTIONAL,
  367. IN PVOID Buffer,
  368. IN ULONG BufferLength
  369. )
  370. /*++
  371. Routine Description:
  372. This routine sends an FSCTL to the server using the previously opened
  373. server handle
  374. Arguments:
  375. ServerControlCode - the FSCTL code to send to the server.
  376. Srp - a pointer to the SRP for the operation.
  377. Buffer - a pointer to the buffer to pass to the server as the
  378. "OutputBuffer" parameter of NtFsControlFile.
  379. BufferLength - the size of this buffer.
  380. Return Value:
  381. NET_API_STATUS - results of the operation.
  382. --*/
  383. {
  384. NTSTATUS status;
  385. NET_API_STATUS error;
  386. IO_STATUS_BLOCK ioStatusBlock;
  387. PSERVER_REQUEST_PACKET sendSrp;
  388. ULONG sendSrpLength;
  389. PWCH name1Buffer, name2Buffer;
  390. HANDLE eventHandle;
  391. if( SsData.SsServerDeviceHandle == NULL ) {
  392. DbgPrint( "SRVSVC: SsData.SsServerDeviceHandle == NULL\n" );
  393. return ERROR_BAD_NET_RESP;
  394. }
  395. //
  396. // If a name was specified, we must capture the SRP along with the
  397. // name in order to avoid sending embedded input pointers.
  398. //
  399. if ( Srp != NULL ) {
  400. name1Buffer = Srp->Name1.Buffer;
  401. name2Buffer = Srp->Name2.Buffer;
  402. if ( Srp->Name1.Buffer != NULL || Srp->Name2.Buffer != NULL ) {
  403. PCHAR nextStringLocation;
  404. //
  405. // Allocate enough space to hold the SRP + name.
  406. //
  407. sendSrpLength = sizeof(SERVER_REQUEST_PACKET);
  408. if ( Srp->Name1.Buffer != NULL ) {
  409. sendSrpLength += Srp->Name1.MaximumLength;
  410. }
  411. if ( Srp->Name2.Buffer != NULL ) {
  412. sendSrpLength += Srp->Name2.MaximumLength;
  413. }
  414. sendSrp = MIDL_user_allocate( sendSrpLength );
  415. if ( sendSrp == NULL ) {
  416. return ERROR_NOT_ENOUGH_MEMORY;
  417. }
  418. //
  419. // Copy over the SRP.
  420. //
  421. RtlCopyMemory( sendSrp, Srp, sizeof(SERVER_REQUEST_PACKET) );
  422. //
  423. // Set up the names in the new SRP.
  424. //
  425. nextStringLocation = (PCHAR)( sendSrp + 1 );
  426. if ( Srp->Name1.Buffer != NULL ) {
  427. sendSrp->Name1.Length = Srp->Name1.Length;
  428. sendSrp->Name1.MaximumLength = Srp->Name1.MaximumLength;
  429. sendSrp->Name1.Buffer = (PWCH)nextStringLocation;
  430. RtlCopyMemory(
  431. sendSrp->Name1.Buffer,
  432. Srp->Name1.Buffer,
  433. Srp->Name1.MaximumLength
  434. );
  435. nextStringLocation += Srp->Name1.MaximumLength;
  436. POINTER_TO_OFFSET( sendSrp->Name1.Buffer, sendSrp );
  437. }
  438. if ( Srp->Name2.Buffer != NULL ) {
  439. sendSrp->Name2.Length = Srp->Name2.Length;
  440. sendSrp->Name2.MaximumLength = Srp->Name2.MaximumLength;
  441. sendSrp->Name2.Buffer = (PWCH)nextStringLocation;
  442. RtlCopyMemory(
  443. sendSrp->Name2.Buffer,
  444. Srp->Name2.Buffer,
  445. Srp->Name2.MaximumLength
  446. );
  447. POINTER_TO_OFFSET( sendSrp->Name2.Buffer, sendSrp );
  448. }
  449. } else {
  450. //
  451. // There was no name in the SRP, so just send the SRP that was
  452. // passed in.
  453. //
  454. sendSrp = Srp;
  455. sendSrpLength = sizeof(SERVER_REQUEST_PACKET);
  456. }
  457. } else {
  458. //
  459. // This request has no SRP.
  460. //
  461. sendSrp = NULL;
  462. sendSrpLength = 0;
  463. }
  464. //
  465. // Create an event to synchronize with the driver
  466. //
  467. status = NtCreateEvent(
  468. &eventHandle,
  469. FILE_ALL_ACCESS,
  470. NULL,
  471. NotificationEvent,
  472. FALSE
  473. );
  474. //
  475. // Send the request to the server FSD.
  476. //
  477. if( NT_SUCCESS( status ) ) {
  478. status = NtFsControlFile(
  479. SsData.SsServerDeviceHandle,
  480. eventHandle,
  481. NULL,
  482. NULL,
  483. &ioStatusBlock,
  484. ServerControlCode,
  485. sendSrp,
  486. sendSrpLength,
  487. Buffer,
  488. BufferLength
  489. );
  490. if( status == STATUS_PENDING ) {
  491. NtWaitForSingleObject( eventHandle, FALSE, NULL );
  492. }
  493. NtClose( eventHandle );
  494. }
  495. //
  496. // If an error code was set in the SRP, use it. Otherwise, if
  497. // an error was returned or set in the IO status block, use that.
  498. //
  499. if ( (sendSrp != NULL) && (sendSrp->ErrorCode != NO_ERROR) ) {
  500. error = sendSrp->ErrorCode;
  501. IF_DEBUG(API_ERRORS) {
  502. SS_PRINT(( "SsServerFsControl: (1) API call %lx to srv failed, "
  503. "err = %ld\n", ServerControlCode, error ));
  504. }
  505. } else {
  506. if ( NT_SUCCESS(status) ) {
  507. status = ioStatusBlock.Status;
  508. }
  509. if ( status == STATUS_SERVER_HAS_OPEN_HANDLES ) {
  510. error = ERROR_SERVER_HAS_OPEN_HANDLES;
  511. } else {
  512. error = NetpNtStatusToApiStatus( status );
  513. }
  514. if ( error != NO_ERROR ) {
  515. IF_DEBUG(API_ERRORS) {
  516. SS_PRINT(( "SsServerFsControl: (2) API call %lx to srv "
  517. "failed, err = %ld, status = %X\n",
  518. ServerControlCode, error, status ));
  519. }
  520. }
  521. }
  522. //
  523. // If a separate buffer was allocated to capture the name, copy
  524. // over the new SRP and free it.
  525. //
  526. if ( sendSrp != Srp ) {
  527. RtlCopyMemory( Srp, sendSrp, sizeof(SERVER_REQUEST_PACKET) );
  528. Srp->Name1.Buffer = name1Buffer;
  529. Srp->Name2.Buffer = name2Buffer;
  530. MIDL_user_free( sendSrp );
  531. }
  532. return error;
  533. } // SsServerFsControl
  534. DWORD
  535. SsGetServerType (
  536. VOID
  537. )
  538. /*++
  539. Routine Description:
  540. Return the ServiceBits of all the services implemented by this service.
  541. Enter with SsData.SsServerInfoResource locked.
  542. Arguments:
  543. None
  544. Return Value:
  545. SV_TYPE service bits.
  546. --*/
  547. {
  548. DWORD serviceBits;
  549. serviceBits = SV_TYPE_SERVER | SV_TYPE_NT | SsData.ServiceBits;
  550. if( SsData.IsDfsRoot ) {
  551. serviceBits |= SV_TYPE_DFS;
  552. }
  553. if ( SsData.ServerInfo599.sv599_timesource ) {
  554. serviceBits |= SV_TYPE_TIME_SOURCE;
  555. }
  556. if ( SsData.ServerInfo598.sv598_producttype == NtProductServer ) {
  557. serviceBits |= SV_TYPE_SERVER_NT;
  558. }
  559. if ( SsData.NumberOfPrintShares != 0 ) {
  560. serviceBits |= SV_TYPE_PRINTQ_SERVER;
  561. }
  562. return serviceBits;
  563. }
  564. VOID
  565. SsSetExportedServerType (
  566. IN PNAME_LIST_ENTRY service OPTIONAL,
  567. IN BOOL ExternalBitsAlreadyChanged,
  568. IN BOOL UpdateImmediately
  569. )
  570. {
  571. DWORD serviceBits;
  572. DWORD newServiceBits;
  573. BOOL changed = ExternalBitsAlreadyChanged;
  574. //
  575. // The value returned in the sv102_type field is an amalgam of the
  576. // following:
  577. //
  578. // 1) The internal server type bits SV_TYPE_SERVER (always set),
  579. // SV_TYPE_NT (always set), SV_TYPE_TIME_SOURCE (set if the
  580. // parameter TimeSource is TRUE), and SV_TYPE_PRINTQ_SERVER (set
  581. // if there are any print shares).
  582. //
  583. // 2) SV_TYPE_DFS if this machine is the root of a DFS tree
  584. //
  585. // 3) The bits set by the service controller calling I_NetServerSetServiceBits.
  586. // SV_TYPE_TIME_SOURCE is a pseudo internal bit. It can be set
  587. // internally or it can be set by the w32time service.
  588. //
  589. // 4) The logical OR of all per-transport server type bits set by
  590. // the Browser calling I_NetServerSetServiceBits.
  591. //
  592. (VOID)RtlAcquireResourceExclusive( &SsData.SsServerInfoResource, TRUE );
  593. serviceBits = SsGetServerType();
  594. if( ARGUMENT_PRESENT( service ) ) {
  595. //
  596. // Change the bits for the passed-in NAME_LIST_ENTRY only
  597. //
  598. newServiceBits = service->ServiceBits;
  599. newServiceBits &= ~(SV_TYPE_SERVER_NT | SV_TYPE_PRINTQ_SERVER | SV_TYPE_DFS);
  600. newServiceBits |= serviceBits;
  601. if( service->ServiceBits != newServiceBits ) {
  602. service->ServiceBits |= newServiceBits;
  603. changed = TRUE;
  604. }
  605. } else {
  606. //
  607. // Change the bits for each NAME_LIST_ENTRY
  608. //
  609. for ( service = SsData.SsServerNameList; service != NULL; service = service->Next ) {
  610. newServiceBits = service->ServiceBits;
  611. newServiceBits &= ~(SV_TYPE_SERVER_NT | SV_TYPE_PRINTQ_SERVER | SV_TYPE_DFS );
  612. newServiceBits |= serviceBits;
  613. if( service->ServiceBits != newServiceBits ) {
  614. service->ServiceBits |= newServiceBits;
  615. changed = TRUE;
  616. }
  617. }
  618. }
  619. RtlReleaseResource( &SsData.SsServerInfoResource );
  620. if ( changed && UpdateImmediately ) {
  621. if( SsData.SsStatusChangedEvent )
  622. {
  623. if ( !SetEvent( SsData.SsStatusChangedEvent ) ) {
  624. SS_PRINT(( "SsSetExportedServerType: SetEvent failed: %ld\n",
  625. GetLastError( ) ));
  626. }
  627. }
  628. }
  629. return;
  630. } // SsSetExportedServerType
  631. NET_API_STATUS
  632. SsSetField (
  633. IN PFIELD_DESCRIPTOR Field,
  634. IN PVOID Value,
  635. IN BOOLEAN WriteToRegistry,
  636. OUT BOOLEAN *AnnouncementInformationChanged OPTIONAL
  637. )
  638. {
  639. PCHAR structure;
  640. //
  641. // *** We do not initialize *AnnouncementInformationChanged to
  642. // FALSE! We leave it alone, unless interesting information is
  643. // changed, in which case we set it to TRUE. This is to allow a
  644. // caller to initialize it itself, then call this function
  645. // multiple times, with the resulting value in the parameter
  646. // being TRUE if at least one of the calls changed an
  647. // interesting parameter.
  648. //
  649. //
  650. // Determine the structure that will be set.
  651. //
  652. if ( Field->Level / 100 == 5 ) {
  653. if ( Field->Level != 598 ) {
  654. structure = (PCHAR)&SsData.ServerInfo599;
  655. } else {
  656. structure = (PCHAR)&SsData.ServerInfo598;
  657. }
  658. } else {
  659. structure = (PCHAR)&SsData.ServerInfo102;
  660. }
  661. //
  662. // Set the value in the field based on the field type.
  663. //
  664. switch ( Field->FieldType ) {
  665. case BOOLEAN_FIELD: {
  666. BOOLEAN value = *(PBOOLEAN)Value;
  667. PBOOLEAN valueLocation;
  668. //
  669. // BOOLEANs may only be TRUE (1) or FALSE (0).
  670. //
  671. if ( value != TRUE && value != FALSE ) {
  672. return ERROR_INVALID_PARAMETER;
  673. }
  674. valueLocation = (PBOOLEAN)( structure + Field->FieldOffset );
  675. //
  676. // If we're turning off Hidden (i.e., making the server public),
  677. // indicate that an announcment-related parameter has changed.
  678. // This will cause an announcement to be sent immediately.
  679. //
  680. if ( (Field->FieldOffset ==
  681. FIELD_OFFSET( SERVER_INFO_102, sv102_hidden )) &&
  682. (value && !(*valueLocation)) &&
  683. (ARGUMENT_PRESENT(AnnouncementInformationChanged)) ) {
  684. *AnnouncementInformationChanged = TRUE;
  685. }
  686. *valueLocation = value;
  687. break;
  688. }
  689. case DWORD_FIELD: {
  690. DWORD value = *(PDWORD)Value;
  691. PDWORD valueLocation;
  692. //
  693. // Make sure that the specified value is in the range of
  694. // legal values for the Field.
  695. //
  696. if ( value > Field->MaximumValue || value < Field->MinimumValue ) {
  697. return ERROR_INVALID_PARAMETER;
  698. }
  699. valueLocation = (PDWORD)( structure + Field->FieldOffset );
  700. *valueLocation = value;
  701. break;
  702. }
  703. case LPSTR_FIELD: {
  704. LPWCH value = *(LPWCH *)Value;
  705. LPWSTR valueLocation;
  706. ULONG maxLength;
  707. //
  708. // We are setting the name, comment, or userpath for the server.
  709. // Use the field offset to determine which.
  710. //
  711. if ( Field->FieldOffset ==
  712. FIELD_OFFSET( SERVER_INFO_102, sv102_name ) ) {
  713. valueLocation = SsData.ServerNameBuffer;
  714. maxLength = sizeof( SsData.SsServerTransportAddress );
  715. } else if ( Field->FieldOffset ==
  716. FIELD_OFFSET( SERVER_INFO_102, sv102_comment ) ) {
  717. valueLocation = SsData.ServerCommentBuffer;
  718. maxLength = MAXCOMMENTSZ;
  719. } else if ( Field->FieldOffset ==
  720. FIELD_OFFSET( SERVER_INFO_102, sv102_userpath ) ) {
  721. valueLocation = SsData.UserPathBuffer;
  722. maxLength = MAX_PATH;
  723. } else if ( Field->FieldOffset ==
  724. FIELD_OFFSET( SERVER_INFO_599, sv599_domain ) ) {
  725. valueLocation = SsData.DomainNameBuffer;
  726. maxLength = DNLEN;
  727. } else {
  728. SS_ASSERT( FALSE );
  729. return ERROR_INVALID_PARAMETER;
  730. }
  731. //
  732. // If the string is too long, return an error.
  733. //
  734. if ( (value != NULL) && (STRLEN(value) > maxLength) ) {
  735. return ERROR_INVALID_PARAMETER;
  736. }
  737. //
  738. // If we're changing the server comment, indicate that an
  739. // announcment-related parameter has changed. This will cause
  740. // an announcement to be sent immediately.
  741. //
  742. if ( (Field->FieldOffset ==
  743. FIELD_OFFSET( SERVER_INFO_102, sv102_comment )) &&
  744. ( ((value == NULL) && (*valueLocation != '\0')) ||
  745. ((value != NULL) && (wcscmp(value,valueLocation) != 0)) ) &&
  746. (ARGUMENT_PRESENT(AnnouncementInformationChanged)) ) {
  747. *AnnouncementInformationChanged = TRUE;
  748. }
  749. //
  750. // If the input is NULL, make the string zero length.
  751. //
  752. if ( value == NULL ) {
  753. *valueLocation = '\0';
  754. *(valueLocation+1) = '\0';
  755. } else {
  756. wcscpy( valueLocation, value );
  757. }
  758. break;
  759. }
  760. } // end switch
  761. //
  762. // The change worked. If requested, add the parameter to the
  763. // registry, thus effecting a sticky change. Don't write it
  764. // to the registry if this is xxx_comment or xxx_disc since
  765. // we already write out their more well known aliases
  766. // srvcomment and autodisconnect. Changes here should also be
  767. // made to SetStickyParameters().
  768. //
  769. if ( WriteToRegistry &&
  770. (_wcsicmp( Field->FieldName, DISC_VALUE_NAME ) != 0) &&
  771. (_wcsicmp( Field->FieldName, COMMENT_VALUE_NAME ) != 0) ) {
  772. SsAddParameterToRegistry( Field, Value );
  773. }
  774. return NO_ERROR;
  775. } // SsSetField
  776. UINT
  777. SsGetDriveType (
  778. IN LPWSTR path
  779. )
  780. /*++
  781. Routine Description:
  782. This routine calls GetDriveType, attempting to eliminate
  783. the DRIVE_NO_ROOT_DIR type
  784. Arguments:
  785. A path
  786. Return Value:
  787. The drive type
  788. --*/
  789. {
  790. UINT driveType = GetDriveType( path );
  791. if( driveType == DRIVE_NO_ROOT_DIR ) {
  792. if( path[0] != UNICODE_NULL && path[1] == L':' ) {
  793. WCHAR shortPath[ 4 ];
  794. shortPath[0] = path[0];
  795. shortPath[1] = L':';
  796. shortPath[2] = L'\\';
  797. shortPath[3] = L'\0';
  798. driveType = GetDriveType( shortPath );
  799. } else {
  800. ULONG len = wcslen( path );
  801. LPWSTR pathWithSlash = MIDL_user_allocate( (len + 2) * sizeof( *path ) );
  802. if( pathWithSlash != NULL ) {
  803. RtlCopyMemory( pathWithSlash, path, len * sizeof( *path ) );
  804. pathWithSlash[ len ] = L'\\';
  805. pathWithSlash[ len+1 ] = L'\0';
  806. driveType = GetDriveType( pathWithSlash );
  807. MIDL_user_free( pathWithSlash );
  808. }
  809. }
  810. }
  811. return driveType;
  812. }
  813. VOID
  814. SsNotifyRdrOfGuid(
  815. LPGUID Guid
  816. )
  817. {
  818. NTSTATUS status;
  819. HANDLE hMrxSmbHandle;
  820. UNICODE_STRING unicodeServerName;
  821. OBJECT_ATTRIBUTES objectAttributes;
  822. IO_STATUS_BLOCK ioStatusBlock;
  823. //
  824. // Open the server device.
  825. //
  826. RtlInitUnicodeString( &unicodeServerName, MRXSMB_DEVICE_NAME );
  827. InitializeObjectAttributes(
  828. &objectAttributes,
  829. &unicodeServerName,
  830. OBJ_CASE_INSENSITIVE,
  831. NULL,
  832. NULL
  833. );
  834. //
  835. // Opening the server with desired access = SYNCHRONIZE and open
  836. // options = FILE_SYNCHRONOUS_IO_NONALERT means that we don't have
  837. // to worry about waiting for the NtFsControlFile to complete--this
  838. // makes all IO system calls that use this handle synchronous.
  839. //
  840. status = NtOpenFile(
  841. &hMrxSmbHandle,
  842. FILE_ALL_ACCESS & ~SYNCHRONIZE,
  843. &objectAttributes,
  844. &ioStatusBlock,
  845. 0,
  846. 0
  847. );
  848. if ( NT_SUCCESS(status) ) {
  849. status = NtFsControlFile( hMrxSmbHandle,
  850. NULL,
  851. NULL,
  852. NULL,
  853. &ioStatusBlock,
  854. FSCTL_LMR_SET_SERVER_GUID,
  855. Guid,
  856. sizeof(GUID),
  857. NULL,
  858. 0 );
  859. NtClose( hMrxSmbHandle );
  860. }
  861. }