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.

1576 lines
42 KiB

  1. /*++
  2. Copyright (c) 1991-1992 Microsoft Corporation
  3. Module Name:
  4. utils.c
  5. Abstract:
  6. Utility routines for the browser service.
  7. Author:
  8. Larry Osterman (LarryO) 23-Mar-1992
  9. Environment:
  10. User Mode - Win32
  11. Revision History:
  12. --*/
  13. #undef IF_DEBUG // avoid wsclient.h vs. debuglib.h conflicts.
  14. #include <nt.h> // DbgPrint prototype
  15. #include <ntrtl.h> // DbgPrint
  16. #include <nturtl.h> // Needed by winbase.h
  17. #include <windef.h> // DWORD
  18. #include <winbase.h> // LocalFree
  19. #include <winreg.h>
  20. #include <rpc.h> // DataTypes and runtime APIs
  21. #include <rpcutil.h> // GENERIC_ENUM_STRUCT
  22. #include <lmcons.h> // NET_API_STATUS
  23. #include <lmerr.h> // NetError codes
  24. #include <lmremutl.h> // SUPPORTS_RPC
  25. #include <netlib.h> // NetpNtStatusToApiStatus
  26. #include <netlibnt.h> // NetpNtStatusToApiStatus
  27. #include <netdebug.h>
  28. #include <bowser.h> // generated by the MIDL complier
  29. #include <brnames.h> // Service and interface names
  30. #include <winsvc.h>
  31. #include <debuglib.h> // IF_DEBUG() (needed by netrpc.h).
  32. #include <lmserver.h>
  33. #include <align.h>
  34. #include <tstr.h>
  35. #include <ntddbrow.h>
  36. #include <brcommon.h> // Routines common between client & server
  37. #include <nb30.h>
  38. #include <hostannc.h>
  39. #include <winnls.h>
  40. #ifdef ENABLE_PSEUDO_BROWSER
  41. #include <config.h> // for LPNET_CONFIG_HANDLE & friends
  42. #include <confname.h> // for SECT_NT_BROWSER
  43. #endif
  44. // begin_setup
  45. //
  46. // Buffer allocation size for enumeration output buffer.
  47. //
  48. #define INITIAL_ALLOCATION_SIZE 48*1024 // First attempt size (48K)
  49. #define FUDGE_FACTOR_SIZE 1024 // Second try TotalBytesNeeded
  50. // plus this amount
  51. //
  52. // prototypes
  53. //
  54. #ifdef ENABLE_PSEUDO_BROWSER
  55. DWORD
  56. IsBrowserEnabled(
  57. IN OPTIONAL LPTSTR Section,
  58. IN LPTSTR Key,
  59. IN BOOL fDefault
  60. );
  61. DWORD
  62. GetBrowserValue(
  63. IN OPTIONAL LPTSTR Section,
  64. IN LPTSTR Key,
  65. OUT PDWORD pdwValue
  66. );
  67. #endif
  68. //
  69. // Implementation
  70. //
  71. NET_API_STATUS
  72. BrDgReceiverIoControlEx(
  73. IN HANDLE FileHandle,
  74. IN ULONG DgReceiverControlCode,
  75. IN PLMDR_REQUEST_PACKET Drp,
  76. IN ULONG DrpSize,
  77. IN PVOID SecondBuffer OPTIONAL,
  78. IN ULONG SecondBufferLength,
  79. OUT PULONG Information OPTIONAL,
  80. IN BOOLEAN WaitForCompletion
  81. )
  82. /*++
  83. Routine Description:
  84. Arguments:
  85. FileHandle - Supplies a handle to the file or device on which the service
  86. is being performed.
  87. DgReceiverControlCode - Supplies the NtDeviceIoControlFile function code
  88. given to the datagram receiver.
  89. Drp - Supplies the datagram receiver request packet.
  90. DrpSize - Supplies the length of the datagram receiver request packet.
  91. SecondBuffer - Supplies the second buffer in call to NtDeviceIoControlFile.
  92. SecondBufferLength - Supplies the length of the second buffer.
  93. Information - Returns the information field of the I/O status block.
  94. Return Value:
  95. NET_API_STATUS - NERR_Success or reason for failure.
  96. --*/
  97. {
  98. NTSTATUS ntstatus;
  99. IO_STATUS_BLOCK IoStatusBlock;
  100. PLMDR_REQUEST_PACKET RealDrp;
  101. HANDLE CompletionEvent;
  102. LPBYTE Where;
  103. if (FileHandle == NULL) {
  104. return ERROR_NOT_SUPPORTED;
  105. }
  106. //
  107. // Allocate a copy of the request packet where we can put the transport and
  108. // emulated domain name in the packet itself.
  109. //
  110. RealDrp = (PLMDR_REQUEST_PACKET) MIDL_user_allocate(DrpSize+
  111. Drp->TransportName.Length+sizeof(WCHAR)+
  112. Drp->EmulatedDomainName.Length+sizeof(WCHAR) );
  113. if (RealDrp == NULL) {
  114. return ERROR_NOT_ENOUGH_MEMORY;
  115. }
  116. //
  117. // Copy the request packet into the local copy.
  118. //
  119. RtlCopyMemory(RealDrp, Drp, DrpSize);
  120. Where = (LPBYTE)RealDrp+DrpSize;
  121. if (Drp->TransportName.Length != 0) {
  122. RealDrp->TransportName.Buffer = (LPWSTR)Where;
  123. RealDrp->TransportName.MaximumLength = Drp->TransportName.Length+sizeof(WCHAR);
  124. RtlCopyUnicodeString(&RealDrp->TransportName, &Drp->TransportName);
  125. Where += RealDrp->TransportName.MaximumLength;
  126. }
  127. if (Drp->EmulatedDomainName.Length != 0) {
  128. RealDrp->EmulatedDomainName.Buffer = (LPWSTR)Where;
  129. RealDrp->EmulatedDomainName.MaximumLength = Drp->EmulatedDomainName.Length+sizeof(WCHAR);
  130. RtlCopyUnicodeString(&RealDrp->EmulatedDomainName, &Drp->EmulatedDomainName);
  131. Where += RealDrp->EmulatedDomainName.MaximumLength;
  132. }
  133. //
  134. // Create a completion event
  135. //
  136. CompletionEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  137. if (CompletionEvent == NULL) {
  138. MIDL_user_free(RealDrp);
  139. return(GetLastError());
  140. }
  141. //
  142. // Send the request to the Datagram Receiver DD.
  143. //
  144. ntstatus = NtDeviceIoControlFile(
  145. FileHandle,
  146. CompletionEvent,
  147. NULL,
  148. NULL,
  149. &IoStatusBlock,
  150. DgReceiverControlCode,
  151. RealDrp,
  152. (ULONG)(Where-(LPBYTE)RealDrp),
  153. SecondBuffer,
  154. SecondBufferLength
  155. );
  156. if (NT_SUCCESS(ntstatus)) {
  157. //
  158. // If we need to wait for completion (synchronous) and
  159. // If pending was returned, then wait until the request completes.
  160. //
  161. if ( WaitForCompletion && (ntstatus == STATUS_PENDING) ) {
  162. do {
  163. ntstatus = WaitForSingleObjectEx(CompletionEvent, 0xffffffff, TRUE);
  164. } while ( ntstatus == WAIT_IO_COMPLETION );
  165. }
  166. if (NT_SUCCESS(ntstatus)) {
  167. ntstatus = IoStatusBlock.Status;
  168. }
  169. }
  170. if (ARGUMENT_PRESENT(Information)) {
  171. *Information = (ULONG)IoStatusBlock.Information;
  172. }
  173. MIDL_user_free(RealDrp);
  174. CloseHandle(CompletionEvent);
  175. return NetpNtStatusToApiStatus(ntstatus);
  176. }
  177. NET_API_STATUS
  178. BrDgReceiverIoControl(
  179. IN HANDLE FileHandle,
  180. IN ULONG DgReceiverControlCode,
  181. IN PLMDR_REQUEST_PACKET Drp,
  182. IN ULONG DrpSize,
  183. IN PVOID SecondBuffer OPTIONAL,
  184. IN ULONG SecondBufferLength,
  185. OUT PULONG Information OPTIONAL
  186. )
  187. {
  188. return BrDgReceiverIoControlEx(
  189. FileHandle,
  190. DgReceiverControlCode,
  191. Drp,
  192. DrpSize,
  193. SecondBuffer,
  194. SecondBufferLength,
  195. Information,
  196. TRUE
  197. );
  198. }
  199. NET_API_STATUS
  200. DeviceControlGetInfo(
  201. IN HANDLE FileHandle,
  202. IN ULONG DeviceControlCode,
  203. IN PVOID RequestPacket,
  204. IN ULONG RequestPacketLength,
  205. OUT LPVOID *OutputBuffer,
  206. IN ULONG PreferedMaximumLength,
  207. IN ULONG BufferHintSize,
  208. OUT PULONG Information OPTIONAL
  209. )
  210. /*++
  211. Routine Description:
  212. This function allocates the buffer and fill it with the information
  213. that is retrieved from the datagram receiver.
  214. Arguments:
  215. DeviceDriverType - Supplies the value which indicates whether to call
  216. the datagram receiver.
  217. FileHandle - Supplies a handle to the file or device of which to get
  218. information about.
  219. DeviceControlCode - Supplies the NtFsControlFile or NtIoDeviceControlFile
  220. function control code.
  221. RequestPacket - Supplies a pointer to the device request packet.
  222. RrequestPacketLength - Supplies the length of the device request packet.
  223. OutputBuffer - Returns a pointer to the buffer allocated by this routine
  224. which contains the use information requested. This pointer is set to
  225. NULL if return code is not NERR_Success.
  226. PreferedMaximumLength - Supplies the number of bytes of information to
  227. return in the buffer. If this value is MAXULONG, we will try to
  228. return all available information if there is enough memory resource.
  229. BufferHintSize - Supplies the hint size of the output buffer so that the
  230. memory allocated for the initial buffer will most likely be large
  231. enough to hold all requested data.
  232. Information - Returns the information code from the NtFsControlFile or
  233. NtIoDeviceControlFile call.
  234. Return Value:
  235. NET_API_STATUS - NERR_Success or reason for failure.
  236. --*/
  237. {
  238. NET_API_STATUS status;
  239. NTSTATUS ntstatus;
  240. DWORD OutputBufferLength;
  241. DWORD TotalBytesNeeded = 1;
  242. ULONG OriginalResumeKey;
  243. IO_STATUS_BLOCK IoStatusBlock;
  244. PLMDR_REQUEST_PACKET Drrp = (PLMDR_REQUEST_PACKET) RequestPacket;
  245. HANDLE CompletionEvent;
  246. OriginalResumeKey = Drrp->Parameters.EnumerateNames.ResumeHandle;
  247. //
  248. // If PreferedMaximumLength is MAXULONG, then we are supposed to get all
  249. // the information, regardless of size. Allocate the output buffer of a
  250. // reasonable size and try to use it. If this fails, the Redirector FSD
  251. // will say how much we need to allocate.
  252. //
  253. if (PreferedMaximumLength == MAXULONG) {
  254. OutputBufferLength = (BufferHintSize) ?
  255. BufferHintSize :
  256. INITIAL_ALLOCATION_SIZE;
  257. }
  258. else {
  259. OutputBufferLength = PreferedMaximumLength;
  260. }
  261. OutputBufferLength = ROUND_UP_COUNT(OutputBufferLength, ALIGN_WCHAR);
  262. if ((*OutputBuffer = MIDL_user_allocate(OutputBufferLength)) == NULL) {
  263. return ERROR_NOT_ENOUGH_MEMORY;
  264. }
  265. RtlZeroMemory((PVOID) *OutputBuffer, OutputBufferLength);
  266. CompletionEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  267. if (CompletionEvent == NULL) {
  268. MIDL_user_free(*OutputBuffer);
  269. *OutputBuffer = NULL;
  270. return(GetLastError());
  271. }
  272. Drrp->Parameters.EnumerateServers.EntriesRead = 0;
  273. //
  274. // Make the request of the Datagram Receiver
  275. //
  276. ntstatus = NtDeviceIoControlFile(
  277. FileHandle,
  278. CompletionEvent,
  279. NULL, // APC routine
  280. NULL, // APC context
  281. &IoStatusBlock,
  282. DeviceControlCode,
  283. Drrp,
  284. RequestPacketLength,
  285. *OutputBuffer,
  286. OutputBufferLength
  287. );
  288. if (NT_SUCCESS(ntstatus)) {
  289. //
  290. // If pending was returned, then wait until the request completes.
  291. //
  292. if (ntstatus == STATUS_PENDING) {
  293. do {
  294. ntstatus = WaitForSingleObjectEx(CompletionEvent, 0xffffffff, TRUE);
  295. } while ( ntstatus == WAIT_IO_COMPLETION );
  296. }
  297. if (NT_SUCCESS(ntstatus)) {
  298. ntstatus = IoStatusBlock.Status;
  299. }
  300. }
  301. //
  302. // Map NT status to Win error
  303. //
  304. status = NetpNtStatusToApiStatus(ntstatus);
  305. if (status == ERROR_MORE_DATA) {
  306. NetpAssert(
  307. FIELD_OFFSET(
  308. LMDR_REQUEST_PACKET,
  309. Parameters.EnumerateNames.TotalBytesNeeded
  310. ) ==
  311. FIELD_OFFSET(
  312. LMDR_REQUEST_PACKET,
  313. Parameters.EnumerateServers.TotalBytesNeeded
  314. )
  315. );
  316. NetpAssert(
  317. FIELD_OFFSET(
  318. LMDR_REQUEST_PACKET,
  319. Parameters.GetBrowserServerList.TotalBytesNeeded
  320. ) ==
  321. FIELD_OFFSET(
  322. LMDR_REQUEST_PACKET,
  323. Parameters.EnumerateServers.TotalBytesNeeded
  324. )
  325. );
  326. TotalBytesNeeded = Drrp->Parameters.EnumerateNames.TotalBytesNeeded;
  327. }
  328. if ((TotalBytesNeeded > OutputBufferLength) &&
  329. (PreferedMaximumLength == MAXULONG)) {
  330. PLMDR_REQUEST_PACKET Drrp = (PLMDR_REQUEST_PACKET) RequestPacket;
  331. //
  332. // Initial output buffer allocated was too small and we need to return
  333. // all data. First free the output buffer before allocating the
  334. // required size plus a fudge factor just in case the amount of data
  335. // grew.
  336. //
  337. MIDL_user_free(*OutputBuffer);
  338. OutputBufferLength =
  339. ROUND_UP_COUNT((TotalBytesNeeded + FUDGE_FACTOR_SIZE),
  340. ALIGN_WCHAR);
  341. if ((*OutputBuffer = MIDL_user_allocate(OutputBufferLength)) == NULL) {
  342. return ERROR_NOT_ENOUGH_MEMORY;
  343. }
  344. RtlZeroMemory((PVOID) *OutputBuffer, OutputBufferLength);
  345. NetpAssert(
  346. FIELD_OFFSET(
  347. LMDR_REQUEST_PACKET,
  348. Parameters.EnumerateNames.ResumeHandle
  349. ) ==
  350. FIELD_OFFSET(
  351. LMDR_REQUEST_PACKET,
  352. Parameters.EnumerateServers.ResumeHandle
  353. )
  354. );
  355. NetpAssert(
  356. FIELD_OFFSET(
  357. LMDR_REQUEST_PACKET,
  358. Parameters.EnumerateNames.ResumeHandle
  359. ) ==
  360. FIELD_OFFSET(
  361. LMDR_REQUEST_PACKET,
  362. Parameters.GetBrowserServerList.ResumeHandle
  363. )
  364. );
  365. Drrp->Parameters.EnumerateNames.ResumeHandle = OriginalResumeKey;
  366. Drrp->Parameters.EnumerateServers.EntriesRead = 0;
  367. //
  368. // Make the request of the Datagram Receiver
  369. //
  370. ntstatus = NtDeviceIoControlFile(
  371. FileHandle,
  372. CompletionEvent,
  373. NULL, // APC routine
  374. NULL, // APC context
  375. &IoStatusBlock,
  376. DeviceControlCode,
  377. Drrp,
  378. RequestPacketLength,
  379. *OutputBuffer,
  380. OutputBufferLength
  381. );
  382. if (NT_SUCCESS(ntstatus)) {
  383. //
  384. // If pending was returned, then wait until the request completes.
  385. //
  386. if (ntstatus == STATUS_PENDING) {
  387. do {
  388. ntstatus = WaitForSingleObjectEx(CompletionEvent, 0xffffffff, TRUE);
  389. } while ( ntstatus == WAIT_IO_COMPLETION );
  390. }
  391. if (NT_SUCCESS(ntstatus)) {
  392. ntstatus = IoStatusBlock.Status;
  393. }
  394. }
  395. status = NetpNtStatusToApiStatus(ntstatus);
  396. }
  397. //
  398. // If not successful in getting any data, or if the caller asked for
  399. // all available data with PreferedMaximumLength == MAXULONG and
  400. // our buffer overflowed, free the output buffer and set its pointer
  401. // to NULL.
  402. //
  403. if ((status != NERR_Success && status != ERROR_MORE_DATA) ||
  404. (TotalBytesNeeded == 0) ||
  405. (PreferedMaximumLength == MAXULONG && status == ERROR_MORE_DATA) ||
  406. (Drrp->Parameters.EnumerateServers.EntriesRead == 0)) {
  407. MIDL_user_free(*OutputBuffer);
  408. *OutputBuffer = NULL;
  409. //
  410. // PreferedMaximumLength == MAXULONG and buffer overflowed means
  411. // we do not have enough memory to satisfy the request.
  412. //
  413. if (status == ERROR_MORE_DATA) {
  414. status = ERROR_NOT_ENOUGH_MEMORY;
  415. }
  416. }
  417. CloseHandle(CompletionEvent);
  418. return status;
  419. UNREFERENCED_PARAMETER(Information);
  420. }
  421. // end_setup
  422. NET_API_STATUS
  423. GetBrowserServerList(
  424. IN PUNICODE_STRING TransportName,
  425. IN LPCWSTR Domain,
  426. OUT LPWSTR *BrowserList[],
  427. OUT PULONG BrowserListLength,
  428. IN BOOLEAN ForceRescan
  429. )
  430. /*++
  431. Routine Description:
  432. This function will return a list of browser servers.
  433. Arguments:
  434. IN PUNICODE_STRING TransportName - Transport to return list.
  435. Return Value:
  436. NET_API_STATUS - NERR_Success or reason for failure.
  437. --*/
  438. {
  439. NET_API_STATUS Status;
  440. HANDLE BrowserHandle;
  441. PLMDR_REQUEST_PACKET RequestPacket = NULL;
  442. // DbgPrint("Getting browser server list for transport %wZ\n", TransportName);
  443. Status = OpenBrowser(&BrowserHandle);
  444. if (Status != NERR_Success) {
  445. return Status;
  446. }
  447. RequestPacket = MIDL_user_allocate(sizeof(LMDR_REQUEST_PACKET)+(DNLEN*sizeof(WCHAR))+TransportName->MaximumLength);
  448. if (RequestPacket == NULL) {
  449. NtClose(BrowserHandle);
  450. return(GetLastError());
  451. }
  452. RequestPacket->Version = LMDR_REQUEST_PACKET_VERSION_DOM;
  453. RequestPacket->Level = 0;
  454. RequestPacket->Parameters.GetBrowserServerList.ForceRescan = ForceRescan;
  455. if (Domain != NULL) {
  456. STRCPY(RequestPacket->Parameters.GetBrowserServerList.DomainName, Domain);
  457. RequestPacket->Parameters.GetBrowserServerList.DomainNameLength = (USHORT)STRLEN(Domain) * sizeof(TCHAR);
  458. } else {
  459. RequestPacket->Parameters.GetBrowserServerList.DomainNameLength = 0;
  460. RequestPacket->Parameters.GetBrowserServerList.DomainName[0] = L'\0';
  461. }
  462. RequestPacket->TransportName.Buffer = (PWSTR)((PCHAR)RequestPacket+sizeof(LMDR_REQUEST_PACKET)+DNLEN*sizeof(WCHAR));
  463. RequestPacket->TransportName.MaximumLength = TransportName->MaximumLength;
  464. RtlCopyUnicodeString(&RequestPacket->TransportName, TransportName);
  465. RtlInitUnicodeString( &RequestPacket->EmulatedDomainName, NULL );
  466. RequestPacket->Parameters.GetBrowserServerList.ResumeHandle = 0;
  467. Status = DeviceControlGetInfo(
  468. BrowserHandle,
  469. IOCTL_LMDR_GET_BROWSER_SERVER_LIST,
  470. RequestPacket,
  471. sizeof(LMDR_REQUEST_PACKET)+
  472. (DNLEN*sizeof(WCHAR))+TransportName->MaximumLength,
  473. (PVOID *)BrowserList,
  474. 0xffffffff,
  475. 4096,
  476. NULL);
  477. if (Status == NERR_Success) {
  478. if ( NULL == *BrowserList ) {
  479. Status = ERROR_NO_BROWSER_SERVERS_FOUND;
  480. }
  481. else {
  482. *BrowserListLength = RequestPacket->Parameters.GetBrowserServerList.EntriesRead;
  483. }
  484. }
  485. NtClose(BrowserHandle);
  486. MIDL_user_free(RequestPacket);
  487. return Status;
  488. }
  489. NET_API_STATUS
  490. OpenBrowserEx(
  491. OUT PHANDLE BrowserHandle,
  492. IN BOOLEAN Synchronous
  493. )
  494. /*++
  495. Routine Description:
  496. This function opens a handle to the bowser device driver.
  497. Arguments:
  498. OUT PHANDLE BrowserHandle - Returns the handle to the browser.
  499. Return Value:
  500. NET_API_STATUS - NERR_Success or reason for failure.
  501. --*/
  502. {
  503. NTSTATUS ntstatus;
  504. UNICODE_STRING DeviceName;
  505. IO_STATUS_BLOCK IoStatusBlock;
  506. OBJECT_ATTRIBUTES ObjectAttributes;
  507. ULONG openOptions;
  508. //
  509. // Open the redirector device.
  510. //
  511. RtlInitUnicodeString(&DeviceName, DD_BROWSER_DEVICE_NAME_U);
  512. InitializeObjectAttributes(
  513. &ObjectAttributes,
  514. &DeviceName,
  515. OBJ_CASE_INSENSITIVE,
  516. NULL,
  517. NULL
  518. );
  519. if (Synchronous) {
  520. openOptions = FILE_SYNCHRONOUS_IO_NONALERT;
  521. }
  522. else {
  523. openOptions = 0;
  524. }
  525. ntstatus = NtOpenFile(
  526. BrowserHandle,
  527. SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE,
  528. &ObjectAttributes,
  529. &IoStatusBlock,
  530. FILE_SHARE_READ | FILE_SHARE_WRITE,
  531. openOptions
  532. );
  533. if (NT_SUCCESS(ntstatus)) {
  534. ntstatus = IoStatusBlock.Status;
  535. }
  536. return NetpNtStatusToApiStatus(ntstatus);
  537. }
  538. NET_API_STATUS
  539. OpenBrowser(
  540. OUT PHANDLE BrowserHandle
  541. )
  542. {
  543. return OpenBrowserEx(BrowserHandle, TRUE);
  544. }
  545. NET_API_STATUS
  546. CheckForService(
  547. IN LPTSTR ServiceName,
  548. OUT LPSERVICE_STATUS ServiceStatus OPTIONAL
  549. )
  550. {
  551. NET_API_STATUS NetStatus;
  552. SC_HANDLE ServiceControllerHandle;
  553. SC_HANDLE ServiceHandle;
  554. SERVICE_STATUS Status;
  555. if (!ARGUMENT_PRESENT(ServiceStatus)) {
  556. ServiceStatus = &Status;
  557. }
  558. ServiceControllerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
  559. if (ServiceControllerHandle == NULL) {
  560. return GetLastError();
  561. }
  562. ServiceHandle = OpenService(ServiceControllerHandle, ServiceName, SERVICE_QUERY_STATUS);
  563. if (ServiceHandle == NULL) {
  564. NetStatus = GetLastError();
  565. CloseServiceHandle(ServiceControllerHandle);
  566. return NetStatus;
  567. }
  568. if (!QueryServiceStatus(ServiceHandle, ServiceStatus)) {
  569. NetStatus = GetLastError();
  570. CloseServiceHandle(ServiceHandle);
  571. CloseServiceHandle(ServiceControllerHandle);
  572. return NetStatus;
  573. }
  574. if ((ServiceStatus->dwCurrentState != SERVICE_RUNNING) &&
  575. (ServiceStatus->dwCurrentState != SERVICE_START_PENDING)) {
  576. CloseServiceHandle(ServiceHandle);
  577. CloseServiceHandle(ServiceControllerHandle);
  578. return(NERR_ServiceNotInstalled);
  579. }
  580. CloseServiceHandle(ServiceHandle);
  581. CloseServiceHandle(ServiceControllerHandle);
  582. return NERR_Success;
  583. }
  584. NET_API_STATUS
  585. BrGetLanaNumFromNetworkName(
  586. IN PWCHAR TransportName,
  587. OUT CCHAR *LanaNum
  588. )
  589. /*++
  590. NOTE: THIS CODE WILL NOT WORK IN THE FUTURE!!!!!!!!!!!!!!
  591. --*/
  592. {
  593. HKEY Key;
  594. LPWSTR BindInformation = NULL;
  595. LPWSTR DevicePointer;
  596. ULONG BindInfoSize = 0;
  597. struct {
  598. CHAR Enumerated;
  599. CHAR LanaNum;
  600. } *LanaMap = NULL;
  601. ULONG LanaMapSize = 0;
  602. NET_API_STATUS Status = ERROR_SUCCESS;
  603. DWORD Type;
  604. DWORD LanaIndex;
  605. LanaIndex = 0;
  606. if (Status = RegOpenKeyEx(
  607. HKEY_LOCAL_MACHINE,
  608. L"System\\CurrentControlSet\\Services\\Netbios\\Linkage",
  609. 0,
  610. KEY_QUERY_VALUE,
  611. &Key))
  612. {
  613. return Status;
  614. }
  615. //
  616. // Get buffers length
  617. //
  618. Status = RegQueryValueEx(
  619. Key,
  620. L"Bind",
  621. 0,
  622. NULL,
  623. NULL,
  624. &BindInfoSize
  625. );
  626. if ( Status != ERROR_SUCCESS ||
  627. BindInfoSize == 0 )
  628. {
  629. goto Cleanup;
  630. }
  631. Status = RegQueryValueEx(
  632. Key,
  633. L"LanaMap",
  634. 0,
  635. NULL,
  636. NULL,
  637. &LanaMapSize
  638. );
  639. if ( Status != ERROR_SUCCESS ||
  640. LanaMapSize == 0 )
  641. {
  642. goto Cleanup;
  643. }
  644. //
  645. // Allocate buffers for data.
  646. //
  647. BindInformation = MIDL_user_allocate(BindInfoSize);
  648. if ( !BindInformation )
  649. {
  650. Status = ERROR_OUTOFMEMORY;
  651. goto Cleanup;
  652. }
  653. LanaMap = MIDL_user_allocate(LanaMapSize);
  654. if ( !LanaMap )
  655. {
  656. Status = ERROR_OUTOFMEMORY;
  657. goto Cleanup;
  658. }
  659. //
  660. // Load values from registry
  661. //
  662. if (Status = RegQueryValueEx(
  663. Key,
  664. L"Bind",
  665. 0,
  666. &Type,
  667. (LPBYTE)BindInformation,
  668. &BindInfoSize))
  669. {
  670. goto Cleanup;
  671. }
  672. if (Status = RegQueryValueEx(
  673. Key,
  674. L"LanaMap",
  675. 0,
  676. &Type,
  677. (LPBYTE)LanaMap,
  678. &LanaMapSize))
  679. {
  680. goto Cleanup;
  681. }
  682. //
  683. // Calculate buffer size
  684. //
  685. DevicePointer = BindInformation;
  686. while (*DevicePointer != UNICODE_NULL) {
  687. if (!_wcsicmp(TransportName, DevicePointer)) {
  688. // found transport
  689. if (LanaMap[LanaIndex].Enumerated != 0) {
  690. *LanaNum = LanaMap[LanaIndex].LanaNum;
  691. Status = NERR_Success;
  692. } else {
  693. Status = ERROR_FILE_NOT_FOUND;
  694. }
  695. goto Cleanup;
  696. }
  697. LanaIndex += 1;
  698. DevicePointer += wcslen(DevicePointer)+1;
  699. }
  700. Cleanup:
  701. if ( BindInformation )
  702. {
  703. MIDL_user_free( BindInformation );
  704. }
  705. if ( LanaMap )
  706. {
  707. MIDL_user_free( LanaMap );
  708. }
  709. RegCloseKey(Key);
  710. return( Status );
  711. }
  712. // 1234567890123456
  713. #define SPACES " "
  714. #define ClearNcb( PNCB ) { \
  715. RtlZeroMemory( PNCB , sizeof (NCB) ); \
  716. RtlCopyMemory( (PNCB)->ncb_name, SPACES, sizeof(SPACES)-1 );\
  717. RtlCopyMemory( (PNCB)->ncb_callname, SPACES, sizeof(SPACES)-1 );\
  718. }
  719. NET_API_STATUS
  720. GetNetBiosMasterName(
  721. IN LPWSTR NetworkName,
  722. IN LPWSTR PrimaryDomain,
  723. OUT LPWSTR MasterName,
  724. IN PSVCS_NET_BIOS_RESET SvcsNetBiosReset OPTIONAL
  725. )
  726. {
  727. CCHAR LanaNum;
  728. NCB AStatNcb;
  729. #define MAX_NETBIOS_NAMES 256
  730. struct {
  731. ADAPTER_STATUS AdapterInfo;
  732. NAME_BUFFER Names[MAX_NETBIOS_NAMES];
  733. } AdapterStatus;
  734. WORD i;
  735. CHAR remoteName[CNLEN+1];
  736. NET_API_STATUS Status;
  737. OEM_STRING OemString;
  738. UNICODE_STRING UnicodeString;
  739. Status = BrGetLanaNumFromNetworkName(NetworkName, &LanaNum);
  740. if (Status != NERR_Success) {
  741. return Status;
  742. }
  743. //
  744. // If the SvcsNetBiosReset argument is present, then this routine is
  745. // being called from the service. In this case it needs to synchronize
  746. // its NetBios Reset with the workstation and the messenger.
  747. //
  748. if (ARGUMENT_PRESENT(SvcsNetBiosReset)) {
  749. SvcsNetBiosReset(LanaNum);
  750. }
  751. else {
  752. ClearNcb(&AStatNcb)
  753. AStatNcb.ncb_command = NCBRESET;
  754. AStatNcb.ncb_lsn = 0; // Request resources
  755. AStatNcb.ncb_lana_num = LanaNum;
  756. AStatNcb.ncb_callname[0] = 0; // 16 sessions
  757. AStatNcb.ncb_callname[1] = 0; // 16 commands
  758. AStatNcb.ncb_callname[2] = 0; // 8 names
  759. AStatNcb.ncb_callname[3] = 0; // Don't want the reserved address
  760. Netbios( &AStatNcb );
  761. }
  762. ClearNcb( &AStatNcb );
  763. //
  764. // Uppercase the remote name.
  765. //
  766. RtlInitUnicodeString(&UnicodeString, PrimaryDomain);
  767. OemString.Buffer=remoteName;
  768. OemString.MaximumLength=sizeof(remoteName);
  769. Status = RtlUpcaseUnicodeStringToOemString(&OemString,
  770. &UnicodeString,
  771. FALSE);
  772. if (!NT_SUCCESS(Status)) {
  773. return RtlNtStatusToDosError(Status);
  774. }
  775. AStatNcb.ncb_command = NCBASTAT;
  776. RtlCopyMemory( AStatNcb.ncb_callname, remoteName, strlen(remoteName));
  777. AStatNcb.ncb_callname[15] = MASTER_BROWSER_SIGNATURE;
  778. AStatNcb.ncb_lana_num = LanaNum;
  779. AStatNcb.ncb_length = sizeof( AdapterStatus );
  780. AStatNcb.ncb_buffer = (CHAR *)&AdapterStatus;
  781. Netbios( &AStatNcb );
  782. if ( AStatNcb.ncb_retcode == NRC_GOODRET ||
  783. AStatNcb.ncb_retcode == NRC_INCOMP ) {
  784. for ( i=0 ; i < min(AdapterStatus.AdapterInfo.name_count, MAX_NETBIOS_NAMES) ; i++ ) {
  785. if (AdapterStatus.Names[i].name[NCBNAMSZ-1] == SERVER_SIGNATURE) {
  786. DWORD j;
  787. //
  788. // Ignore malformed netbios names.
  789. //
  790. // Some transports have strange netbios names. For instance,
  791. // netbt registers a netbios name where the first 12 bytes
  792. // are 0 and the last 4 bytes are the IP address.
  793. //
  794. for ( j = 0 ; j < CNLEN ; j++ ) {
  795. if (AdapterStatus.Names[i].name[j] == '\0') {
  796. break;
  797. }
  798. }
  799. if ( j != CNLEN ) {
  800. continue;
  801. }
  802. //
  803. // Convert to unicode
  804. //
  805. if (MultiByteToWideChar(CP_OEMCP,
  806. 0,
  807. AdapterStatus.Names[i].name,
  808. CNLEN,
  809. MasterName,
  810. CNLEN) == 0) {
  811. return(GetLastError());
  812. }
  813. for (j = CNLEN - 1; j ; j -= 1) {
  814. if (MasterName[j] != L' ') {
  815. MasterName[j+1] = UNICODE_NULL;
  816. break;
  817. }
  818. }
  819. return NERR_Success;
  820. }
  821. }
  822. return AStatNcb.ncb_retcode;
  823. } else {
  824. return AStatNcb.ncb_retcode;
  825. }
  826. }
  827. NET_API_STATUS
  828. SendDatagramEx(
  829. IN HANDLE DgReceiverHandle,
  830. IN PUNICODE_STRING Network,
  831. IN PUNICODE_STRING EmulatedDomainName,
  832. IN PWSTR ResponseName,
  833. IN DGRECEIVER_NAME_TYPE NameType,
  834. IN PVOID Buffer,
  835. IN ULONG BufferLength,
  836. IN BOOLEAN Synchronous
  837. )
  838. {
  839. NET_API_STATUS Status;
  840. ULONG IOCTLCode;
  841. UCHAR PacketBuffer[sizeof(LMDR_REQUEST_PACKET)+(LM20_CNLEN+1)*sizeof(WCHAR)];
  842. PLMDR_REQUEST_PACKET RequestPacket = (PLMDR_REQUEST_PACKET)PacketBuffer;
  843. RequestPacket->Version = LMDR_REQUEST_PACKET_VERSION_DOM;
  844. RequestPacket->TransportName = *Network;
  845. RequestPacket->EmulatedDomainName = *EmulatedDomainName;
  846. RequestPacket->Type = Datagram;
  847. RequestPacket->Parameters.SendDatagram.DestinationNameType = NameType;
  848. RequestPacket->Parameters.SendDatagram.MailslotNameLength = 0;
  849. //
  850. // The domain announcement name is special, so we don't have to specify
  851. // a destination name for it.
  852. //
  853. RequestPacket->Parameters.SendDatagram.NameLength = wcslen(ResponseName)*sizeof(WCHAR);
  854. wcscpy(RequestPacket->Parameters.SendDatagram.Name, ResponseName);
  855. //
  856. // This is a simple IoControl - It just sends the datagram.
  857. //
  858. if ( Synchronous ) {
  859. IOCTLCode = IOCTL_LMDR_WRITE_MAILSLOT;
  860. }
  861. else {
  862. IOCTLCode = IOCTL_LMDR_WRITE_MAILSLOT_ASYNC;
  863. }
  864. Status = BrDgReceiverIoControlEx(DgReceiverHandle,
  865. IOCTLCode,
  866. RequestPacket,
  867. FIELD_OFFSET(LMDR_REQUEST_PACKET, Parameters.SendDatagram.Name)+
  868. RequestPacket->Parameters.SendDatagram.NameLength,
  869. Buffer,
  870. BufferLength,
  871. NULL,
  872. Synchronous
  873. );
  874. return Status;
  875. }
  876. NET_API_STATUS
  877. SendDatagram(
  878. IN HANDLE DgReceiverHandle,
  879. IN PUNICODE_STRING Network,
  880. IN PUNICODE_STRING EmulatedDomainName,
  881. IN PWSTR ResponseName,
  882. IN DGRECEIVER_NAME_TYPE NameType,
  883. IN PVOID Buffer,
  884. IN ULONG BufferLength
  885. )
  886. {
  887. return SendDatagramEx(
  888. DgReceiverHandle,
  889. Network,
  890. EmulatedDomainName,
  891. ResponseName,
  892. NameType,
  893. Buffer,
  894. BufferLength,
  895. TRUE
  896. );
  897. }
  898. #ifdef ENABLE_PSEUDO_BROWSER
  899. DWORD
  900. GetBrowserValue(
  901. IN OPTIONAL LPTSTR Section,
  902. IN LPTSTR Key,
  903. OUT PDWORD pdwValue
  904. )
  905. /*++
  906. Routine Description:
  907. Query Registry for browser DWORD value.
  908. Arguments:
  909. Section: registry section to query
  910. Key: Key to query value.
  911. Return Value:
  912. ERROR_SUCCESS: Got value
  913. Win32 error: failed to get value
  914. --*/
  915. {
  916. DWORD status = NERR_Success;
  917. LPNET_CONFIG_HANDLE BrowserSection;
  918. const DWORD dwDefault = 0;
  919. NetpAssert(pdwValue);
  920. if ( Section ) {
  921. //
  922. // Open specified section
  923. // (usually used for policy propagation & such)
  924. //
  925. if (NetpOpenConfigDataWithPath(
  926. &BrowserSection,
  927. NULL,
  928. Section,
  929. TRUE) != NERR_Success) {
  930. return ERROR_CANTREAD;
  931. }
  932. }
  933. else {
  934. //
  935. // Open default browser section
  936. //
  937. if (NetpOpenConfigData(
  938. &BrowserSection,
  939. NULL,
  940. SECT_NT_BROWSER,
  941. TRUE) != NERR_Success) {
  942. return ERROR_CANTREAD;
  943. }
  944. }
  945. //
  946. // Get config value
  947. //
  948. if ( NetpGetConfigDword(
  949. BrowserSection,
  950. Key,
  951. dwDefault,
  952. pdwValue ) ) {
  953. // free handle & return failure (default's assigned already)
  954. NetpCloseConfigData(BrowserSection);
  955. return (ERROR_CANTREAD);
  956. }
  957. // free handle
  958. NetpCloseConfigData(BrowserSection);
  959. //
  960. // Hack: Net api missing key fixup
  961. //
  962. if ( Section ){
  963. //
  964. // If explicit path was specified we distinguish missing key
  965. // from when the key is set. However Net api return
  966. // success (assuming default) if the key is missing.
  967. // Thus, upon success we query below for the key's existance.
  968. // Justification: We need to know when a policy key was
  969. // specified or not. However for default net section we can
  970. // accept default value. That is, we assume proper call order:
  971. // 1. query policy --> if specified accept, if missing -->
  972. // 2. query net default location --> if missing or error accept
  973. // default.
  974. // So why don't we just use our own? Cause net api has it standards
  975. // such as [yes|no] equiv to [DWORD(1)|DWORD(0)], default locations
  976. // and more.
  977. //
  978. HKEY SectionKey = NULL;
  979. DWORD cbData;
  980. LPWSTR pwszSection;
  981. const LPWSTR wszParameters = L"\\Parameters";
  982. // alloc & copy fixed up section name
  983. cbData = (wcslen(Section) + wcslen(wszParameters) + 1) * sizeof(WCHAR);
  984. pwszSection = MIDL_user_allocate(cbData);
  985. if (!pwszSection) {
  986. return (ERROR_CANTREAD);
  987. }
  988. wcscpy(pwszSection, Section);
  989. wcscat(pwszSection, wszParameters);
  990. status = RegOpenKeyEx (
  991. HKEY_LOCAL_MACHINE,
  992. pwszSection,
  993. REG_OPTION_NON_VOLATILE,
  994. KEY_READ,
  995. &SectionKey );
  996. if (status) {
  997. //
  998. // Can't even open the key.
  999. //
  1000. MIDL_user_free( pwszSection );
  1001. return (ERROR_CANTREAD);
  1002. }
  1003. // free mem & query value.
  1004. MIDL_user_free( pwszSection );
  1005. cbData = 0;
  1006. status = RegQueryValueEx(
  1007. SectionKey,
  1008. Key,
  1009. 0,
  1010. NULL,
  1011. NULL,
  1012. &cbData );
  1013. if ( status != ERROR_SUCCESS ||
  1014. cbData == 0) {
  1015. //
  1016. // Key's not there or failed to get it
  1017. //
  1018. RegCloseKey(SectionKey);
  1019. return (ERROR_CANTREAD);
  1020. }
  1021. RegCloseKey(SectionKey);
  1022. }
  1023. // Got value
  1024. return (ERROR_SUCCESS);
  1025. }
  1026. DWORD
  1027. IsBrowserEnabled(
  1028. IN OPTIONAL LPTSTR Section,
  1029. IN LPTSTR Key,
  1030. IN BOOL fDefault
  1031. )
  1032. /*++
  1033. Routine Description:
  1034. Query Registry for browser boolean state.
  1035. Arguments:
  1036. Section: registry section to query
  1037. Key: Key to query value.
  1038. Return Value:
  1039. ERROR_SUCCESS: Browser marked enabled.
  1040. ERROR_SERVICE_DISABLED: Browser marked disabled.
  1041. ERROR_CANTREAD: No regkey found or can't open.
  1042. --*/
  1043. {
  1044. DWORD status = NERR_Success;
  1045. LPNET_CONFIG_HANDLE BrowserSection;
  1046. BOOL fEnabled = fDefault;
  1047. if ( Section ) {
  1048. //
  1049. // Open specified section
  1050. // (usually used for policy propagation & such)
  1051. //
  1052. if (NetpOpenConfigDataWithPath(
  1053. &BrowserSection,
  1054. NULL,
  1055. Section,
  1056. TRUE) != NERR_Success) {
  1057. return ERROR_CANTREAD;
  1058. }
  1059. }
  1060. else {
  1061. //
  1062. // Open default browser section
  1063. //
  1064. if (NetpOpenConfigData(
  1065. &BrowserSection,
  1066. NULL,
  1067. SECT_NT_BROWSER,
  1068. TRUE) != NERR_Success) {
  1069. return ERROR_CANTREAD;
  1070. }
  1071. }
  1072. //
  1073. // Get config value
  1074. //
  1075. if ( NetpGetConfigBool(
  1076. BrowserSection,
  1077. Key,
  1078. fDefault,
  1079. &fEnabled
  1080. ) ) {
  1081. // free handle & return failure (default's assigned already)
  1082. NetpCloseConfigData(BrowserSection);
  1083. return (ERROR_CANTREAD);
  1084. }
  1085. // free handle
  1086. NetpCloseConfigData(BrowserSection);
  1087. //
  1088. // Hack: Net api missing key fixup
  1089. //
  1090. if ( Section ){
  1091. //
  1092. // If explicit path was specified we distinguish missing key
  1093. // from when the key is set. However Net api return
  1094. // success (assuming default) if the key is missing.
  1095. // Thus, upon success we query below for the key's existance.
  1096. // Justification: We need to know when a policy key was
  1097. // specified or not. However for default net section we can
  1098. // accept default value. That is, we assume proper call order:
  1099. // 1. query policy --> if specified accept, if missing -->
  1100. // 2. query net default location --> if missing or error accept
  1101. // default.
  1102. // So why don't we just use our own? Cause net api has it standards
  1103. // such as [yes|no] equiv to [DWORD(1)|DWORD(0)], default locations
  1104. // and more.
  1105. //
  1106. HKEY SectionKey = NULL;
  1107. DWORD cbData;
  1108. LPWSTR pwszSection;
  1109. const LPWSTR wszParameters = L"\\Parameters";
  1110. // alloc & copy fixed up section name
  1111. cbData = (wcslen(Section) + wcslen(wszParameters) + 1) * sizeof(WCHAR);
  1112. pwszSection = MIDL_user_allocate(cbData);
  1113. if (!pwszSection) {
  1114. return (ERROR_CANTREAD);
  1115. }
  1116. wcscpy(pwszSection, Section);
  1117. wcscat(pwszSection, wszParameters);
  1118. status = RegOpenKeyEx (
  1119. HKEY_LOCAL_MACHINE,
  1120. pwszSection,
  1121. REG_OPTION_NON_VOLATILE,
  1122. KEY_READ,
  1123. &SectionKey );
  1124. if (status) {
  1125. //
  1126. // Can't even open the key.
  1127. //
  1128. MIDL_user_free( pwszSection );
  1129. return (ERROR_CANTREAD);
  1130. }
  1131. // free mem & query value.
  1132. MIDL_user_free( pwszSection );
  1133. cbData = 0;
  1134. status = RegQueryValueEx(
  1135. SectionKey,
  1136. Key,
  1137. 0,
  1138. NULL,
  1139. NULL,
  1140. &cbData );
  1141. if ( status != ERROR_SUCCESS ||
  1142. cbData == 0) {
  1143. //
  1144. // Key's not there or failed to get it
  1145. //
  1146. RegCloseKey(SectionKey);
  1147. return (ERROR_CANTREAD);
  1148. }
  1149. RegCloseKey(SectionKey);
  1150. }
  1151. // got value, return state.
  1152. return ( fEnabled ? ERROR_SUCCESS :
  1153. ERROR_SERVICE_DISABLED);
  1154. }
  1155. BOOL
  1156. IsEnumServerEnabled(
  1157. VOID
  1158. )
  1159. /*++
  1160. Routine Description:
  1161. Query the Registry to find if NetServerEnum functionality has
  1162. been disabled by an admin.
  1163. Arguments:
  1164. None.
  1165. Return Value:
  1166. FALSE: service is marked disabled.
  1167. TRUE: default or service is marked enabled
  1168. Remarks:
  1169. None.
  1170. --*/
  1171. {
  1172. DWORD status;
  1173. const BOOL fDefault = TRUE;
  1174. //
  1175. // Query default section
  1176. //
  1177. status = IsBrowserEnabled(
  1178. BROWSER_POLICY_REGPATH_W,
  1179. BROWSER_SEND_SERVER_ENUM_REGKEY_W,
  1180. fDefault);
  1181. if ( status == ERROR_SUCCESS ) {
  1182. // policy marked enabled.
  1183. return TRUE;
  1184. }
  1185. else if ( status == ERROR_SERVICE_DISABLED ) {
  1186. // policy marked disabled
  1187. return FALSE;
  1188. }
  1189. // else failed to read, thus try default (local) service location.
  1190. //
  1191. // Query default section
  1192. //
  1193. status = IsBrowserEnabled(
  1194. NULL,
  1195. BROWSER_SEND_SERVER_ENUM_REGKEY_W,
  1196. fDefault);
  1197. if ( status == ERROR_SERVICE_DISABLED ) {
  1198. // marked disabled
  1199. return FALSE;
  1200. }
  1201. // else either ERROR_SUCCESS (i.e. enabled)
  1202. // or error (default to enabled)
  1203. NetpAssert(fDefault);
  1204. // default is enabled.
  1205. return fDefault;
  1206. }
  1207. DWORD
  1208. GetBrowserPseudoServerLevel(
  1209. VOID
  1210. )
  1211. /*++
  1212. Routine Description:
  1213. Query the Registry to find if this machine should act
  1214. as a Pseudo Server (in case it's a master browser)
  1215. Arguments:
  1216. None.
  1217. Return Value:
  1218. FALSE: default or server is not a Pseudo Server.
  1219. TRUE: service is marked as Pseudo Server.
  1220. Remarks:
  1221. None.
  1222. --*/
  1223. {
  1224. DWORD status;
  1225. const DWORD dwDefault = BROWSER_NON_PSEUDO;
  1226. DWORD dwLevel = dwDefault;
  1227. //
  1228. // Query policy & then browser sections
  1229. //
  1230. if ( ERROR_SUCCESS == GetBrowserValue(
  1231. BROWSER_POLICY_REGPATH_W,
  1232. BROWSER_PSEUDO_SERVER_REGKEY_W,
  1233. &dwLevel) ||
  1234. ERROR_SUCCESS == GetBrowserValue(
  1235. NULL,
  1236. BROWSER_PSEUDO_SERVER_REGKEY_W,
  1237. &dwLevel) ) {
  1238. // policy level exits
  1239. if ( dwLevel != BROWSER_NON_PSEUDO &&
  1240. dwLevel != BROWSER_SEMI_PSEUDO_NO_DMB &&
  1241. dwLevel != BROWSER_PSEUDO ) {
  1242. NetpAssert(!"Regkey browser pseudo level set to invalid value");
  1243. return dwDefault;
  1244. }
  1245. return dwLevel;
  1246. }
  1247. // else failed to read all sections, use default.
  1248. return dwDefault;
  1249. }
  1250. #endif