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.

1493 lines
35 KiB

  1. //++
  2. //
  3. // Copyright (C) Microsoft Corporation, 1987 - 1999
  4. //
  5. // Module Name:
  6. //
  7. // nwtest.c
  8. //
  9. // Abstract:
  10. //
  11. // Queries into network drivers
  12. //
  13. // Author:
  14. //
  15. // Anilth - 4-20-1998
  16. //
  17. // Environment:
  18. //
  19. // User mode only.
  20. // Contains NT-specific code.
  21. //
  22. // Revision History:
  23. //
  24. //--
  25. #include "precomp.h"
  26. #include "nwtest.h"
  27. HRESULT
  28. NetwareTest(NETDIAG_PARAMS* pParams, NETDIAG_RESULT* pResults)
  29. //++
  30. //
  31. // Description:
  32. // This routine enumerates bindery or tree logins and in the case of tree login gives the
  33. // default context.
  34. // It also gets the server attached to.
  35. //
  36. // Argument:
  37. // None.
  38. //
  39. // Author:
  40. // Rajkumar .P 07/21/98
  41. //
  42. {
  43. // PTESTED_DOMAIN Context = pParams->pDomain;
  44. LPWSTR pszCurrentContext = NULL;
  45. DWORD dwPrintOptions;
  46. LPWSTR pszName;
  47. WCHAR szUserName[MAX_PATH+1] = L"";
  48. WCHAR szNoName[2] = L"";
  49. DWORD_PTR ResumeKey = 0;
  50. LPBYTE pBuffer = NULL;
  51. DWORD EntriesRead = 0;
  52. DWORD dwMessageId;
  53. UNICODE_STRING uContext;
  54. WCHAR szContext[MAX_PATH+1];
  55. LPWSTR pszTemp;
  56. // Get the current default tree or server name
  57. DWORD err ;
  58. PCONN_STATUS pConnStatus = NULL;
  59. DWORD i;
  60. PCONN_STATUS pConnStatusTmp;
  61. PCONN_STATUS pConnStatusUser;
  62. PCONN_STATUS pConnStatusNoUser;
  63. HANDLE handleRdr;
  64. LPWSTR pszText;
  65. // WNet calls related declarations;
  66. DWORD dwError;
  67. LPNETRESOURCE lpNetResource = NULL;
  68. HANDLE hEnum;
  69. DWORD dwCount;
  70. LPNETRESOURCE lpBuffer;
  71. DWORD BufferSize;
  72. HRESULT hr = hrOK;
  73. InitializeListHead( &pResults->Netware.lmsgOutput );
  74. PrintStatusMessage(pParams, 4, IDS_NETWARE_STATUS_MSG);
  75. //
  76. // Check if client services for netware has been installed
  77. //
  78. /*
  79. dwError = WNetOpenEnum(
  80. RESOURCE_GLOBALNET,
  81. RESOURCETYPE_ANY | RESOURCETYPE_PRINT | RESOURCETYPE_DISK,
  82. 0,
  83. lpNetResource,
  84. &hEnum);
  85. if (dwError != NO_ERROR) {
  86. if (dwError == ERROR_NO_NETWORK)
  87. printf("No Network is present\n");
  88. printf("WNetOpenEnum failed. Not Able to determine client services for netware is installed\n");
  89. return FALSE;
  90. }
  91. lpBuffer = LocalAlloc(LMEM_ZEROINIT,sizeof(NETRESOURCE) * 100); // arbit
  92. dwError = WNetEnumResource(
  93. hEnum,
  94. &dwCount,
  95. lpBuffer,
  96. &BufferSize);
  97. if (dwError != NO_ERROR) {
  98. if (DebugVerbose)
  99. printf("Error: WNetEnumResource\n");
  100. if (dwError == ERROR_NO_MORE_ITEMS)
  101. printf("ERROR_NO_MORE_ITEM\n");
  102. dwError = GetLastError();
  103. if (dwError == ERROR_MORE_DATA) {
  104. if (DebugVerbose)
  105. printf("ERROR_MORE_DATA\n");
  106. }
  107. if (dwError == ERROR_INVALID_HANDLE)
  108. printf("ERROR_INVALID_HANDLE\n");
  109. if (dwError == ERROR_NO_NETWORK)
  110. printf("ERROR_NO_NETWORK\n");
  111. if (dwError == ERROR_EXTENDED_ERROR)
  112. printf("ERROR_EXTENDED_ERROR\n");
  113. }
  114. else {
  115. printf("dwCount %d \n",dwCount);
  116. }
  117. LocalFree(lpBuffer);
  118. */
  119. // end of WNet calls
  120. err = NwQueryInfo( &dwPrintOptions, &pszCurrentContext );
  121. if ( err == NO_ERROR )
  122. {
  123. szContext[0] = 0;
  124. uContext.Buffer = szContext;
  125. uContext.Length = uContext.MaximumLength
  126. = sizeof(szContext)/sizeof(szContext[0]);
  127. if ( pszCurrentContext )
  128. {
  129. pszName = pszCurrentContext;
  130. }
  131. else
  132. {
  133. pszName = szNoName;
  134. }
  135. if ( pszName[0] == TREECHAR )
  136. {
  137. // Get the tree name from the full name *TREE\CONTEXT
  138. if ( pszTemp = wcschr( pszName, L'\\' ))
  139. *pszTemp = 0;
  140. dwMessageId = NW_MESSAGE_NOT_LOGGED_IN_TREE;
  141. }
  142. else
  143. {
  144. dwMessageId = NW_MESSAGE_NOT_LOGGED_IN_SERVER;
  145. }
  146. if ( pszName[0] != 0 ) // there is preferred server/tree
  147. {
  148. err = NwGetConnectionStatus( pszName,
  149. &ResumeKey,
  150. &pBuffer,
  151. &EntriesRead );
  152. }
  153. if ( err == NO_ERROR && EntriesRead > 0 )
  154. // For trees, we'll get more than one entry
  155. {
  156. pConnStatus = (PCONN_STATUS) pBuffer;
  157. if ( EntriesRead > 1 && pszName[0] == TREECHAR )
  158. {
  159. // If there is more than one entry for trees,
  160. // then we need to find one entry where username is not null.
  161. // If we cannot find one, then just use the first one.
  162. pConnStatusTmp = pConnStatus;
  163. pConnStatusUser = NULL;
  164. pConnStatusNoUser = NULL;
  165. for ( i = 0; i < EntriesRead ; i++ )
  166. {
  167. if ( pConnStatusTmp->fNds )
  168. {
  169. pConnStatusNoUser = pConnStatusTmp;
  170. if ( ( pConnStatusTmp->pszUserName != NULL )
  171. && ( ( pConnStatusTmp->dwConnType
  172. == NW_CONN_NDS_AUTHENTICATED_NO_LICENSE )
  173. || ( pConnStatusTmp->dwConnType
  174. == NW_CONN_NDS_AUTHENTICATED_LICENSED )
  175. )
  176. )
  177. {
  178. // Found it
  179. pConnStatusUser = pConnStatusTmp;
  180. break;
  181. }
  182. }
  183. // Continue with the next item
  184. pConnStatusTmp = (PCONN_STATUS)
  185. ( (DWORD_PTR) pConnStatusTmp
  186. + pConnStatusTmp->dwTotalLength);
  187. }
  188. if ( pConnStatusUser )
  189. {
  190. // found one nds entry with a user name
  191. pConnStatus = pConnStatusUser;
  192. }
  193. else if ( pConnStatusNoUser )
  194. {
  195. // use an nds entry with no user name
  196. pConnStatus = pConnStatusNoUser;
  197. }
  198. // else use the first entry
  199. }
  200. if ( ( pConnStatus->pszUserName )
  201. && ( pConnStatus->pszUserName[0] != 0 )
  202. )
  203. {
  204. NwAbbreviateUserName( pConnStatus->pszUserName,
  205. szUserName);
  206. NwMakePrettyDisplayName( szUserName );
  207. if ( pszName[0] != TREECHAR )
  208. {
  209. dwMessageId = NW_MESSAGE_LOGGED_IN_SERVER;
  210. }
  211. else
  212. {
  213. dwMessageId = NW_MESSAGE_LOGGED_IN_TREE;
  214. }
  215. }
  216. if ( pszName[0] == TREECHAR )
  217. {
  218. // For trees, we need to get the current context
  219. // Open a handle to the redirector
  220. handleRdr = NULL;
  221. err = RtlNtStatusToDosError(
  222. NwNdsOpenRdrHandle( &handleRdr ));
  223. if ( err == NO_ERROR )
  224. {
  225. UNICODE_STRING uTree;
  226. RtlInitUnicodeString( &uTree, pszName+1 ); // get past '*'
  227. // Get the current context in the default tree
  228. err = RtlNtStatusToDosError(
  229. NwNdsGetTreeContext( handleRdr,
  230. &uTree,
  231. &uContext));
  232. }
  233. if ( handleRdr != NULL )
  234. NtClose( handleRdr );
  235. }
  236. }
  237. if ( !err )
  238. {
  239. switch (dwMessageId)
  240. {
  241. case NW_MESSAGE_NOT_LOGGED_IN_TREE:
  242. // "You are not logged in to the directory tree %s. "
  243. AddMessageToList(&pResults->Netware.lmsgOutput,
  244. Nd_Quiet,
  245. IDS_NETWARE_NOT_LOGGED_IN_TREE,
  246. pszName[0] == TREECHAR ? pszName + 1: pszName);
  247. hr = S_FALSE;
  248. break;
  249. case NW_MESSAGE_NOT_LOGGED_IN_SERVER:
  250. // "You are not logged in to your preferred server %s.\n"
  251. AddMessageToList(&pResults->Netware.lmsgOutput,
  252. Nd_Quiet,
  253. IDS_NETWARE_NOT_LOGGED_IN_SERVER,
  254. pszName[0] == TREECHAR ? pszName + 1: pszName);
  255. hr = S_FALSE;
  256. break;
  257. case NW_MESSAGE_LOGGED_IN_SERVER:
  258. // "You are logged in to the server %s with user name %s.\n"
  259. AddMessageToList(&pResults->Netware.lmsgOutput,
  260. Nd_Verbose,
  261. IDS_NETWARE_LOGGED_IN_SERVER,
  262. pszName[0] == TREECHAR ? pszName + 1: pszName,
  263. szUserName);
  264. pResults->Netware.pszServer = StrDupTFromW(pszName[0] == TREECHAR ?
  265. pszName + 1 : pszName);
  266. pResults->Netware.pszUser = StrDupTFromW(szUserName);
  267. pResults->Netware.pszTree = StrDup(_T(""));
  268. pResults->Netware.pszContext = StrDup(_T(""));
  269. break;
  270. case NW_MESSAGE_LOGGED_IN_TREE:
  271. // "You are logged in to the directory tree %s with user name %s.\nThe current workstation name context is %s.\n"
  272. AddMessageToList(&pResults->Netware.lmsgOutput,
  273. Nd_Verbose,
  274. IDS_NETWARE_LOGGED_IN_TREE,
  275. pszName[0] == TREECHAR ? pszName + 1: pszName,
  276. szUserName,
  277. szContext);
  278. pResults->Netware.pszTree = StrDupTFromW(pszName[0] == TREECHAR ?
  279. pszName + 1 : pszName);
  280. pResults->Netware.pszUser = StrDupTFromW(szUserName);
  281. pResults->Netware.pszContext = StrDupTFromW(szContext);
  282. pResults->Netware.pszServer = StrDup(_T(""));
  283. }
  284. // Read from the conn status if possible
  285. if (pConnStatus)
  286. {
  287. pResults->Netware.fConnStatus = TRUE;
  288. if (pConnStatus->pszUserName)
  289. {
  290. Free(pResults->Netware.pszUser);
  291. pResults->Netware.pszUser =
  292. StrDupTFromW(pConnStatus->pszUserName);
  293. }
  294. if (pConnStatus->pszServerName)
  295. {
  296. Free(pResults->Netware.pszServer);
  297. pResults->Netware.pszServer =
  298. StrDupTFromW(pConnStatus->pszServerName);
  299. }
  300. if (pConnStatus->pszTreeName)
  301. {
  302. Free(pResults->Netware.pszTree);
  303. pResults->Netware.pszTree =
  304. StrDupTFromW(pConnStatus->pszTreeName);
  305. }
  306. pResults->Netware.fNds = pConnStatus->fNds;
  307. pResults->Netware.dwConnType = pConnStatus->dwConnType;
  308. }
  309. else
  310. pResults->Netware.fConnStatus = FALSE;
  311. }
  312. if ( pBuffer != NULL )
  313. {
  314. LocalFree( pBuffer );
  315. pBuffer = NULL;
  316. }
  317. }
  318. if ( pszCurrentContext != NULL )
  319. {
  320. LocalFree( pszCurrentContext );
  321. pszCurrentContext = NULL;
  322. }
  323. if ( err != NO_ERROR )
  324. {
  325. // if (DebugVerbose)
  326. // printf("Error %s occurred while trying to get connection information.\n",err);
  327. // printf("Error getting connection information\n");
  328. hr = S_FALSE;
  329. }
  330. return hr;
  331. }
  332. WORD
  333. NwParseNdsUncPath(
  334. IN OUT LPWSTR * Result,
  335. IN LPWSTR ContainerName,
  336. IN ULONG flag
  337. )
  338. /*++
  339. Routine Description:
  340. This function is used to extract either the tree name, fully distinguished
  341. name path to an object, or object name, out of a complete NDS UNC path.
  342. Arguments:
  343. Result - parsed result buffer.
  344. ContainerName - Complete NDS UNC path that is to be parsed.
  345. flag - Flag indicating operation to be performed:
  346. PARSE_NDS_GET_TREE_NAME
  347. PARSE_NDS_GET_PATH_NAME
  348. PARSE_NDS_GET_OBJECT_NAME
  349. Return Value:
  350. Length of string in result buffer. If error occured, 0 is returned.
  351. --*/ // NwParseNdsUncPath
  352. {
  353. USHORT length = 2;
  354. USHORT totalLength = (USHORT) wcslen( ContainerName );
  355. if ( totalLength < 2 )
  356. return 0;
  357. //
  358. // First get length to indicate the character in the string that indicates the
  359. // "\" in between the tree name and the rest of the UNC path.
  360. //
  361. // Example: \\<tree name>\<path to object>[\|.]<object>
  362. // ^
  363. // |
  364. //
  365. while ( length < totalLength && ContainerName[length] != L'\\' )
  366. {
  367. length++;
  368. }
  369. if ( flag == PARSE_NDS_GET_TREE_NAME )
  370. {
  371. *Result = (LPWSTR) ( ContainerName + 2 );
  372. return ( length - 2 ) * sizeof( WCHAR ); // Take off 2 for the two \\'s
  373. }
  374. if ( flag == PARSE_NDS_GET_PATH_NAME && length == totalLength )
  375. {
  376. *Result = ContainerName;
  377. return 0;
  378. }
  379. if ( flag == PARSE_NDS_GET_PATH_NAME )
  380. {
  381. *Result = ContainerName + length + 1;
  382. return ( totalLength - length - 1 ) * sizeof( WCHAR );
  383. }
  384. *Result = ContainerName + totalLength - 1;
  385. length = 1;
  386. while ( **Result != L'\\' )
  387. {
  388. *Result--;
  389. length++;
  390. }
  391. *Result++;
  392. length--;
  393. return length * sizeof( WCHAR );
  394. }
  395. NTSTATUS NwNdsOpenRdrHandle(
  396. OUT PHANDLE phNwRdrHandle
  397. )
  398. {
  399. NTSTATUS ntstatus;
  400. IO_STATUS_BLOCK IoStatusBlock;
  401. OBJECT_ATTRIBUTES ObjectAttributes;
  402. ACCESS_MASK DesiredAccess = SYNCHRONIZE | GENERIC_READ;
  403. WCHAR NameStr[] = L"\\Device\\NwRdr\\*";
  404. UNICODE_STRING uOpenName;
  405. //
  406. // Prepare the open name.
  407. //
  408. RtlInitUnicodeString( &uOpenName, NameStr );
  409. //
  410. // Set up the object attributes.
  411. //
  412. InitializeObjectAttributes(
  413. &ObjectAttributes,
  414. &uOpenName,
  415. OBJ_CASE_INSENSITIVE,
  416. NULL,
  417. NULL );
  418. ntstatus = NtOpenFile(
  419. phNwRdrHandle,
  420. DesiredAccess,
  421. &ObjectAttributes,
  422. &IoStatusBlock,
  423. FILE_SHARE_VALID_FLAGS,
  424. FILE_SYNCHRONOUS_IO_NONALERT );
  425. if ( !NT_ERROR(ntstatus) &&
  426. !NT_INFORMATION(ntstatus) &&
  427. !NT_WARNING(ntstatus)) {
  428. return IoStatusBlock.Status;
  429. }
  430. return ntstatus;
  431. }
  432. NTSTATUS
  433. NwNdsGetTreeContext (
  434. IN HANDLE hNdsRdr,
  435. IN PUNICODE_STRING puTree,
  436. OUT PUNICODE_STRING puContext
  437. )
  438. /*+++
  439. This gets the current context of the requested tree.
  440. ---*/
  441. {
  442. NTSTATUS ntstatus;
  443. IO_STATUS_BLOCK IoStatusBlock;
  444. PNWR_NDS_REQUEST_PACKET Rrp;
  445. DWORD RrpSize;
  446. //
  447. // Set up the request.
  448. //
  449. RrpSize = sizeof( NWR_NDS_REQUEST_PACKET ) + puTree->Length;
  450. Rrp = LocalAlloc( LMEM_ZEROINIT, RrpSize );
  451. if ( !Rrp ) {
  452. return STATUS_INSUFFICIENT_RESOURCES;
  453. }
  454. try {
  455. (Rrp->Parameters).GetContext.TreeNameLen = puTree->Length;
  456. RtlCopyMemory( (BYTE *)(Rrp->Parameters).GetContext.TreeNameString,
  457. puTree->Buffer,
  458. puTree->Length );
  459. (Rrp->Parameters).GetContext.Context.MaximumLength = puContext->MaximumLength;
  460. (Rrp->Parameters).GetContext.Context.Length = 0;
  461. (Rrp->Parameters).GetContext.Context.Buffer = puContext->Buffer;
  462. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  463. ntstatus = STATUS_INVALID_PARAMETER;
  464. goto ExitWithCleanup;
  465. }
  466. try {
  467. ntstatus = NtFsControlFile( hNdsRdr,
  468. NULL,
  469. NULL,
  470. NULL,
  471. &IoStatusBlock,
  472. FSCTL_NWR_NDS_GETCONTEXT,
  473. (PVOID) Rrp,
  474. RrpSize,
  475. NULL,
  476. 0 );
  477. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  478. ntstatus = GetExceptionCode();
  479. goto ExitWithCleanup;
  480. }
  481. //
  482. // Copy out the length; the buffer has already been written.
  483. //
  484. puContext->Length = (Rrp->Parameters).GetContext.Context.Length;
  485. ExitWithCleanup:
  486. LocalFree( Rrp );
  487. return ntstatus;
  488. }
  489. DWORD
  490. NwGetConnectionStatus(
  491. IN LPWSTR pszRemoteName,
  492. OUT PDWORD_PTR ResumeKey,
  493. OUT LPBYTE *Buffer,
  494. OUT PDWORD EntriesRead
  495. )
  496. {
  497. DWORD err = NO_ERROR;
  498. DWORD dwBytesNeeded = 0;
  499. DWORD dwBufferSize = TWO_KB;
  500. *Buffer = NULL;
  501. *EntriesRead = 0;
  502. do {
  503. *Buffer = (LPBYTE) LocalAlloc( LMEM_ZEROINIT, dwBufferSize );
  504. if ( *Buffer == NULL )
  505. return ERROR_NOT_ENOUGH_MEMORY;
  506. err = NWPGetConnectionStatus( pszRemoteName,
  507. ResumeKey,
  508. *Buffer,
  509. dwBufferSize,
  510. &dwBytesNeeded,
  511. EntriesRead );
  512. if ( err == ERROR_INSUFFICIENT_BUFFER )
  513. {
  514. dwBufferSize = dwBytesNeeded + EXTRA_BYTES;
  515. LocalFree( *Buffer );
  516. *Buffer = NULL;
  517. }
  518. } while ( err == ERROR_INSUFFICIENT_BUFFER );
  519. if ( err == ERROR_INVALID_PARAMETER ) // not attached
  520. {
  521. err = NO_ERROR;
  522. *EntriesRead = 0;
  523. }
  524. return err;
  525. }
  526. VOID
  527. NwAbbreviateUserName(
  528. IN LPWSTR pszFullName,
  529. OUT LPWSTR pszUserName
  530. )
  531. {
  532. LPWSTR pszTemp;
  533. LPWSTR pszLast;
  534. WCHAR NextChar;
  535. if ( pszUserName == NULL )
  536. return;
  537. pszTemp = pszFullName;
  538. pszLast = pszTemp;
  539. *pszUserName = 0;
  540. while ( pszTemp = wcschr( pszTemp, L'='))
  541. {
  542. NextChar = *(++pszTemp);
  543. while ( NextChar != 0 && NextChar != L'.' )
  544. {
  545. *(pszUserName++) = *pszTemp;
  546. NextChar = *(++pszTemp);
  547. }
  548. if ( NextChar == 0 )
  549. {
  550. pszLast = NULL;
  551. break;
  552. }
  553. *(pszUserName++) = *pszTemp; // put back the '.'
  554. pszLast = ++pszTemp;
  555. }
  556. if ( pszLast != NULL )
  557. {
  558. while ( *pszLast != 0 )
  559. *(pszUserName++) = *(pszLast++);
  560. }
  561. *pszUserName = 0;
  562. }
  563. VOID
  564. NwMakePrettyDisplayName(
  565. IN LPWSTR pszName
  566. )
  567. {
  568. if ( pszName )
  569. {
  570. CharLower((LPSTR)pszName );
  571. CharUpperBuff( (LPSTR)pszName, 1);
  572. }
  573. }
  574. DWORD
  575. NWPGetConnectionStatus(
  576. IN LPWSTR pszRemoteName,
  577. IN OUT PDWORD_PTR ResumeKey,
  578. OUT LPBYTE Buffer,
  579. IN DWORD BufferSize,
  580. OUT PDWORD BytesNeeded,
  581. OUT PDWORD EntriesRead
  582. )
  583. {
  584. NTSTATUS ntstatus = STATUS_SUCCESS;
  585. HANDLE handleRdr = NULL;
  586. OBJECT_ATTRIBUTES ObjectAttributes;
  587. IO_STATUS_BLOCK IoStatusBlock;
  588. UNICODE_STRING uRdrName;
  589. WCHAR RdrPrefix[] = L"\\Device\\NwRdr\\*";
  590. PNWR_REQUEST_PACKET RequestPacket = NULL;
  591. DWORD RequestPacketSize = 0;
  592. DWORD dwRemoteNameLen = 0;
  593. //
  594. // Set up the object attributes.
  595. //
  596. RtlInitUnicodeString( &uRdrName, RdrPrefix );
  597. InitializeObjectAttributes( &ObjectAttributes,
  598. &uRdrName,
  599. OBJ_CASE_INSENSITIVE,
  600. NULL,
  601. NULL );
  602. ntstatus = NtOpenFile( &handleRdr,
  603. SYNCHRONIZE | FILE_LIST_DIRECTORY,
  604. &ObjectAttributes,
  605. &IoStatusBlock,
  606. FILE_SHARE_VALID_FLAGS,
  607. FILE_SYNCHRONOUS_IO_NONALERT );
  608. if ( !NT_SUCCESS(ntstatus) )
  609. goto CleanExit;
  610. dwRemoteNameLen = pszRemoteName? wcslen(pszRemoteName)*sizeof(WCHAR) : 0;
  611. RequestPacketSize = sizeof( NWR_REQUEST_PACKET ) + dwRemoteNameLen;
  612. RequestPacket = (PNWR_REQUEST_PACKET) LocalAlloc( LMEM_ZEROINIT,
  613. RequestPacketSize );
  614. if ( RequestPacket == NULL )
  615. {
  616. ntstatus = STATUS_NO_MEMORY;
  617. goto CleanExit;
  618. }
  619. //
  620. // Fill out the request packet for FSCTL_NWR_GET_CONN_STATUS.
  621. //
  622. RequestPacket->Parameters.GetConnStatus.ResumeKey = *ResumeKey;
  623. RequestPacket->Version = REQUEST_PACKET_VERSION;
  624. RequestPacket->Parameters.GetConnStatus.ConnectionNameLength = dwRemoteNameLen;
  625. RtlCopyMemory( &(RequestPacket->Parameters.GetConnStatus.ConnectionName[0]),
  626. pszRemoteName,
  627. dwRemoteNameLen );
  628. ntstatus = NtFsControlFile( handleRdr,
  629. NULL,
  630. NULL,
  631. NULL,
  632. &IoStatusBlock,
  633. FSCTL_NWR_GET_CONN_STATUS,
  634. (PVOID) RequestPacket,
  635. RequestPacketSize,
  636. (PVOID) Buffer,
  637. BufferSize );
  638. if ( NT_SUCCESS( ntstatus ))
  639. ntstatus = IoStatusBlock.Status;
  640. *EntriesRead = RequestPacket->Parameters.GetConnStatus.EntriesReturned;
  641. *ResumeKey = RequestPacket->Parameters.GetConnStatus.ResumeKey;
  642. *BytesNeeded = RequestPacket->Parameters.GetConnStatus.BytesNeeded;
  643. CleanExit:
  644. if ( handleRdr != NULL )
  645. NtClose( handleRdr );
  646. if ( RequestPacket != NULL )
  647. LocalFree( RequestPacket );
  648. return RtlNtStatusToDosError( ntstatus );
  649. }
  650. BOOL
  651. NwIsNdsSyntax(
  652. IN LPWSTR lpstrUnc
  653. )
  654. {
  655. HANDLE hTreeConn;
  656. DWORD dwOid;
  657. DWORD status = NO_ERROR;
  658. if ( lpstrUnc == NULL )
  659. return FALSE;
  660. status = NwOpenAndGetTreeInfo( lpstrUnc, &hTreeConn, &dwOid );
  661. if ( status != NO_ERROR )
  662. {
  663. return FALSE;
  664. }
  665. CloseHandle( hTreeConn );
  666. return TRUE;
  667. }
  668. DWORD
  669. NwOpenAndGetTreeInfo(
  670. LPWSTR pszNdsUNCPath,
  671. HANDLE *phTreeConn,
  672. DWORD *pdwOid
  673. )
  674. {
  675. NTSTATUS ntstatus = STATUS_SUCCESS;
  676. WCHAR lpServerName[NW_MAX_SERVER_LEN];
  677. UNICODE_STRING ServerName;
  678. UNICODE_STRING ObjectName;
  679. *phTreeConn = NULL;
  680. ServerName.Length = 0;
  681. ServerName.MaximumLength = sizeof( lpServerName );
  682. ServerName.Buffer = lpServerName;
  683. ObjectName.Buffer = NULL;
  684. ObjectName.MaximumLength = ( wcslen( pszNdsUNCPath) + 1 ) * sizeof( WCHAR );
  685. ObjectName.Length = NwParseNdsUncPath( (LPWSTR *) &ObjectName.Buffer,
  686. pszNdsUNCPath,
  687. PARSE_NDS_GET_TREE_NAME );
  688. if ( ObjectName.Length == 0 || ObjectName.Buffer == NULL )
  689. {
  690. return ERROR_PATH_NOT_FOUND;
  691. }
  692. //
  693. // Open a NDS tree connection handle to \\treename
  694. //
  695. ntstatus = NwNdsOpenTreeHandle( &ObjectName, phTreeConn );
  696. if ( !NT_SUCCESS( ntstatus ))
  697. {
  698. return RtlNtStatusToDosError( ntstatus );
  699. }
  700. //
  701. // Get the path to the container to open.
  702. //
  703. ObjectName.Length = NwParseNdsUncPath( (LPWSTR *) &ObjectName.Buffer,
  704. pszNdsUNCPath,
  705. PARSE_NDS_GET_PATH_NAME );
  706. if ( ObjectName.Length == 0 )
  707. {
  708. UNICODE_STRING Root;
  709. RtlInitUnicodeString(&Root, L"[Root]");
  710. //
  711. // Resolve the path to get a NDS object id.
  712. //
  713. ntstatus = NwNdsResolveName( *phTreeConn,
  714. &Root,
  715. pdwOid,
  716. &ServerName,
  717. NULL,
  718. 0 );
  719. }
  720. else
  721. {
  722. //
  723. // Resolve the path to get a NDS object id.
  724. //
  725. ntstatus = NwNdsResolveName( *phTreeConn,
  726. &ObjectName,
  727. pdwOid,
  728. &ServerName,
  729. NULL,
  730. 0 );
  731. }
  732. if ( ntstatus == STATUS_SUCCESS && ServerName.Length )
  733. {
  734. DWORD dwHandleType;
  735. //
  736. // NwNdsResolveName succeeded, but we were referred to
  737. // another server, though pdwOid is still valid.
  738. if ( *phTreeConn )
  739. CloseHandle( *phTreeConn );
  740. *phTreeConn = NULL;
  741. //
  742. // Open a NDS generic connection handle to \\ServerName
  743. //
  744. ntstatus = NwNdsOpenGenericHandle( &ServerName,
  745. &dwHandleType,
  746. phTreeConn );
  747. if ( ntstatus != STATUS_SUCCESS )
  748. {
  749. return RtlNtStatusToDosError(ntstatus);
  750. }
  751. ASSERT( dwHandleType != HANDLE_TYPE_NCP_SERVER );
  752. }
  753. if ( !NT_SUCCESS( ntstatus ))
  754. {
  755. if ( *phTreeConn != NULL )
  756. {
  757. CloseHandle( *phTreeConn );
  758. *phTreeConn = NULL;
  759. }
  760. return RtlNtStatusToDosError(ntstatus);
  761. }
  762. return NO_ERROR;
  763. }
  764. static
  765. DWORD
  766. NwRegQueryValueExW(
  767. IN HKEY hKey,
  768. IN LPWSTR lpValueName,
  769. OUT LPDWORD lpReserved,
  770. OUT LPDWORD lpType,
  771. OUT LPBYTE lpData,
  772. IN OUT LPDWORD lpcbData
  773. )
  774. /*++
  775. Routine Description:
  776. This routine supports the same functionality as Win32 RegQueryValueEx
  777. API, except that it works. It returns the correct lpcbData value when
  778. a NULL output buffer is specified.
  779. This code is stolen from the service controller.
  780. Arguments:
  781. same as RegQueryValueEx
  782. Return Value:
  783. NO_ERROR or reason for failure.
  784. --*/
  785. {
  786. NTSTATUS ntstatus;
  787. UNICODE_STRING ValueName;
  788. PKEY_VALUE_FULL_INFORMATION KeyValueInfo;
  789. DWORD BufSize;
  790. UNREFERENCED_PARAMETER(lpReserved);
  791. //
  792. // Make sure we have a buffer size if the buffer is present.
  793. //
  794. if ((ARGUMENT_PRESENT(lpData)) && (! ARGUMENT_PRESENT(lpcbData))) {
  795. return ERROR_INVALID_PARAMETER;
  796. }
  797. RtlInitUnicodeString(&ValueName, lpValueName);
  798. //
  799. // Allocate memory for the ValueKeyInfo
  800. //
  801. BufSize = *lpcbData + sizeof(KEY_VALUE_FULL_INFORMATION) +
  802. ValueName.Length
  803. - sizeof(WCHAR); // subtract memory for 1 char because it's included
  804. // in the sizeof(KEY_VALUE_FULL_INFORMATION).
  805. KeyValueInfo = (PKEY_VALUE_FULL_INFORMATION) LocalAlloc(
  806. LMEM_ZEROINIT,
  807. (UINT) BufSize
  808. );
  809. if (KeyValueInfo == NULL) {
  810. // if (DebugVerbose)
  811. // printf("NWWORKSTATION: NwRegQueryValueExW: LocalAlloc failed %lu\n",
  812. // GetLastError());
  813. return ERROR_NOT_ENOUGH_MEMORY;
  814. }
  815. ntstatus = NtQueryValueKey(
  816. hKey,
  817. &ValueName,
  818. KeyValueFullInformation,
  819. (PVOID) KeyValueInfo,
  820. (ULONG) BufSize,
  821. (PULONG) &BufSize
  822. );
  823. if ((NT_SUCCESS(ntstatus) || (ntstatus == STATUS_BUFFER_OVERFLOW))
  824. && ARGUMENT_PRESENT(lpcbData)) {
  825. *lpcbData = KeyValueInfo->DataLength;
  826. }
  827. if (NT_SUCCESS(ntstatus)) {
  828. if (ARGUMENT_PRESENT(lpType)) {
  829. *lpType = KeyValueInfo->Type;
  830. }
  831. if (ARGUMENT_PRESENT(lpData)) {
  832. memcpy(
  833. lpData,
  834. (LPBYTE)KeyValueInfo + KeyValueInfo->DataOffset,
  835. KeyValueInfo->DataLength
  836. );
  837. }
  838. }
  839. (void) LocalFree((HLOCAL) KeyValueInfo);
  840. return RtlNtStatusToDosError(ntstatus);
  841. }
  842. DWORD
  843. NwReadRegValue(
  844. IN HKEY Key,
  845. IN LPWSTR ValueName,
  846. OUT LPWSTR *Value
  847. )
  848. /*++
  849. Routine Description:
  850. This function allocates the output buffer and reads the requested
  851. value from the registry into it.
  852. Arguments:
  853. Key - Supplies opened handle to the key to read from.
  854. ValueName - Supplies name of the value to retrieve data.
  855. Value - Returns a pointer to the output buffer which points to
  856. the memory allocated and contains the data read in from the
  857. registry. This pointer must be freed with LocalFree when done.
  858. Return Value:
  859. ERROR_NOT_ENOUGH_MEMORY - Failed to create buffer to read value into.
  860. Error from registry call.
  861. --*/
  862. {
  863. LONG RegError;
  864. DWORD NumRequired = 0;
  865. DWORD ValueType;
  866. //
  867. // Set returned buffer pointer to NULL.
  868. //
  869. *Value = NULL;
  870. RegError = NwRegQueryValueExW(
  871. Key,
  872. ValueName,
  873. NULL,
  874. &ValueType,
  875. (LPBYTE) NULL,
  876. &NumRequired
  877. );
  878. if (RegError != ERROR_SUCCESS && NumRequired > 0) {
  879. if ((*Value = (LPWSTR) LocalAlloc(
  880. LMEM_ZEROINIT,
  881. (UINT) NumRequired
  882. )) == NULL) {
  883. // if (DebugVerbose)
  884. // printf("NWWORKSTATION: NwReadRegValue: LocalAlloc of size %lu failed %lu\n", NumRequired, GetLastError());
  885. //
  886. return ERROR_NOT_ENOUGH_MEMORY;
  887. }
  888. RegError = NwRegQueryValueExW(
  889. Key,
  890. ValueName,
  891. NULL,
  892. &ValueType,
  893. (LPBYTE) *Value,
  894. &NumRequired
  895. );
  896. }
  897. else if (RegError == ERROR_SUCCESS) {
  898. // if (DebugVerbose)
  899. // printf("NWWORKSTATION: NwReadRegValue got SUCCESS with NULL buffer.");
  900. return ERROR_FILE_NOT_FOUND;
  901. }
  902. if (RegError != ERROR_SUCCESS) {
  903. if (*Value != NULL) {
  904. (void) LocalFree((HLOCAL) *Value);
  905. *Value = NULL;
  906. }
  907. return (DWORD) RegError;
  908. }
  909. return NO_ERROR;
  910. }
  911. DWORD
  912. NwpGetCurrentUserRegKey(
  913. IN DWORD DesiredAccess,
  914. OUT HKEY *phKeyCurrentUser
  915. )
  916. /*++
  917. Routine Description:
  918. This routine opens the current user's registry key under
  919. \HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\NWCWorkstation\Parameters
  920. Arguments:
  921. DesiredAccess - The access mask to open the key with
  922. phKeyCurrentUser - Receives the opened key handle
  923. Return Value:
  924. Returns the appropriate Win32 error.
  925. --*/
  926. {
  927. DWORD err;
  928. HKEY hkeyWksta;
  929. LPWSTR CurrentUser;
  930. DWORD Disposition;
  931. //
  932. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  933. // \NWCWorkstation\Parameters
  934. //
  935. err = RegOpenKeyExW(
  936. HKEY_LOCAL_MACHINE,
  937. NW_WORKSTATION_REGKEY,
  938. REG_OPTION_NON_VOLATILE,
  939. KEY_READ,
  940. &hkeyWksta
  941. );
  942. if ( err ) {
  943. // if (DebugVerbose)
  944. // printf("NWPROVAU: NwGetCurrentUserRegKey open Paramters key unexpected error %lu!\n",err);
  945. return err;
  946. }
  947. //
  948. // Get the current user's SID string.
  949. //
  950. err = NwReadRegValue(
  951. hkeyWksta,
  952. NW_CURRENTUSER_VALUENAME,
  953. &CurrentUser
  954. );
  955. if ( err ) {
  956. // if (DebugVerbose)
  957. // printf("NWPROVAU: NwGetCurrentUserRegKey read CurrentUser value unexpected error %lu !\n", err);
  958. (void) RegCloseKey( hkeyWksta );
  959. return err;
  960. }
  961. (void) RegCloseKey( hkeyWksta );
  962. //
  963. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  964. // \NWCWorkstation\Parameters\Option
  965. //
  966. err = RegOpenKeyExW(
  967. HKEY_LOCAL_MACHINE,
  968. NW_WORKSTATION_OPTION_REGKEY,
  969. REG_OPTION_NON_VOLATILE,
  970. KEY_READ,
  971. &hkeyWksta
  972. );
  973. if ( err ) {
  974. // if (DebugVerbose)
  975. // printf("NWPROVAU: NwGetCurrentUserRegKey open Parameters\\Option key unexpected error %lu!\n", err);
  976. return err;
  977. }
  978. //
  979. // Open current user's key
  980. //
  981. err = RegOpenKeyExW(
  982. hkeyWksta,
  983. CurrentUser,
  984. REG_OPTION_NON_VOLATILE,
  985. DesiredAccess,
  986. phKeyCurrentUser
  987. );
  988. if ( err == ERROR_FILE_NOT_FOUND)
  989. {
  990. //
  991. // Create <NewUser> key under NWCWorkstation\Parameters\Option
  992. //
  993. err = RegCreateKeyExW(
  994. hkeyWksta,
  995. CurrentUser,
  996. 0,
  997. WIN31_CLASS,
  998. REG_OPTION_NON_VOLATILE,
  999. DesiredAccess,
  1000. NULL, // security attr
  1001. phKeyCurrentUser,
  1002. &Disposition
  1003. );
  1004. }
  1005. if ( err ) {
  1006. // if (DebugVerbose)
  1007. // printf("NWPROVAU: NwGetCurrentUserRegKey open or create of Parameters\\Option\\%ws key failed %lu\n", CurrentUser, err);
  1008. }
  1009. (void) RegCloseKey( hkeyWksta );
  1010. (void) LocalFree((HLOCAL)CurrentUser) ;
  1011. return err;
  1012. }
  1013. DWORD
  1014. NwQueryInfo(
  1015. OUT PDWORD pnPrintOptions,
  1016. OUT LPWSTR *ppszPreferredSrv
  1017. )
  1018. /*++
  1019. Routine Description:
  1020. This routine gets the user's preferred server and print options from
  1021. the registry.
  1022. Arguments:
  1023. pnPrintOptions - Receives the user's print option
  1024. ppszPreferredSrv - Receives the user's preferred server
  1025. Return Value:
  1026. Returns the appropriate Win32 error.
  1027. --*/
  1028. {
  1029. HKEY hKeyCurrentUser = NULL;
  1030. DWORD BufferSize;
  1031. DWORD BytesNeeded;
  1032. DWORD PrintOption;
  1033. DWORD ValueType;
  1034. LPWSTR PreferredServer ;
  1035. DWORD err ;
  1036. //
  1037. // get to right place in registry and allocate dthe buffer
  1038. //
  1039. if (err = NwpGetCurrentUserRegKey( KEY_READ, &hKeyCurrentUser))
  1040. {
  1041. //
  1042. // If somebody mess around with the registry and we can't find
  1043. // the registry, just use the defaults.
  1044. //
  1045. *ppszPreferredSrv = NULL;
  1046. // *pnPrintOptions = NW_PRINT_OPTION_DEFAULT;
  1047. return NO_ERROR;
  1048. }
  1049. BufferSize = sizeof(WCHAR) * (MAX_PATH + 2) ;
  1050. PreferredServer = (LPWSTR) LocalAlloc(LPTR, BufferSize) ;
  1051. if (!PreferredServer)
  1052. return (GetLastError()) ;
  1053. //
  1054. // Read PreferredServer value into Buffer.
  1055. //
  1056. BytesNeeded = BufferSize ;
  1057. err = RegQueryValueExW( hKeyCurrentUser,
  1058. NW_SERVER_VALUENAME,
  1059. NULL,
  1060. &ValueType,
  1061. (LPBYTE) PreferredServer,
  1062. &BytesNeeded );
  1063. if (err != NO_ERROR)
  1064. {
  1065. //
  1066. // set to empty and carry on
  1067. //
  1068. PreferredServer[0] = 0;
  1069. }
  1070. if (hKeyCurrentUser != NULL)
  1071. (void) RegCloseKey(hKeyCurrentUser) ;
  1072. *ppszPreferredSrv = PreferredServer ;
  1073. return NO_ERROR ;
  1074. }
  1075. /*!--------------------------------------------------------------------------
  1076. NetwareGlobalPrint
  1077. -
  1078. Author: KennT
  1079. ---------------------------------------------------------------------------*/
  1080. void NetwareGlobalPrint( NETDIAG_PARAMS* pParams,
  1081. NETDIAG_RESULT* pResults)
  1082. {
  1083. int ids;
  1084. LPTSTR pszConnType;
  1085. if (!pResults->Ipx.fEnabled)
  1086. {
  1087. return;
  1088. }
  1089. if (pParams->fVerbose || !FHrOK(pResults->Netware.hr))
  1090. {
  1091. BOOL fVerboseT, fReallyVerboseT;
  1092. PrintNewLine(pParams, 2);
  1093. PrintMessage(pParams, IDS_NETWARE_TITLE_MSG);
  1094. fVerboseT = pParams->fVerbose;
  1095. fReallyVerboseT = pParams->fReallyVerbose;
  1096. pParams->fReallyVerbose = TRUE;
  1097. PrintMessageList(pParams, &pResults->Netware.lmsgOutput);
  1098. pParams->fReallyVerbose = fReallyVerboseT;
  1099. pParams->fVerbose = fVerboseT;
  1100. // Now print out the results
  1101. if (FHrOK(pResults->Netware.hr))
  1102. {
  1103. // Print out the user name, server name, tree and context
  1104. PrintMessage(pParams,
  1105. IDS_NETWARE_USER_NAME,
  1106. pResults->Netware.pszUser == 0 ? _T("") : pResults->Netware.pszUser);
  1107. PrintMessage(pParams,
  1108. IDS_NETWARE_SERVER_NAME,
  1109. pResults->Netware.pszServer == 0 ? _T("") : pResults->Netware.pszServer);
  1110. PrintMessage(pParams,
  1111. IDS_NETWARE_TREE_NAME,
  1112. pResults->Netware.pszTree == 0 ? _T("") : pResults->Netware.pszTree);
  1113. PrintMessage(pParams,
  1114. IDS_NETWARE_CONTEXT,
  1115. pResults->Netware.pszContext == 0 ? _T("") : pResults->Netware.pszContext);
  1116. // Print out the connection type and nds
  1117. if (pResults->Netware.fConnStatus)
  1118. {
  1119. PrintMessage(pParams,
  1120. IDS_NETWARE_NDS,
  1121. MAP_YES_NO(pResults->Netware.fNds));
  1122. switch (pResults->Netware.dwConnType)
  1123. {
  1124. case NW_CONN_NOT_AUTHENTICATED:
  1125. ids = IDS_NETWARE_CONN_NOT_AUTHENTICATED;
  1126. break;
  1127. case NW_CONN_BINDERY_LOGIN:
  1128. ids = IDS_NETWARE_CONN_BINDERY_LOGIN;
  1129. break;
  1130. case NW_CONN_NDS_AUTHENTICATED_NO_LICENSE:
  1131. ids = IDS_NETWARE_CONN_NDS_AUTHENTICATED_NO_LICENSE;
  1132. break;
  1133. case NW_CONN_NDS_AUTHENTICATED_LICENSED:
  1134. ids = IDS_NETWARE_CONN_NDS_AUTHENTICATED_LICENSED;
  1135. break;
  1136. case NW_CONN_DISCONNECTED:
  1137. ids = IDS_NETWARE_CONN_DISCONNECTED;
  1138. break;
  1139. default:
  1140. ids = IDS_NETWARE_CONN_UNKNOWN;
  1141. break;
  1142. }
  1143. PrintMessage(pParams,
  1144. ids,
  1145. pResults->Netware.dwConnType);
  1146. }
  1147. }
  1148. }
  1149. }
  1150. /*!--------------------------------------------------------------------------
  1151. NetwarePerInterfacePrint
  1152. -
  1153. Author: KennT
  1154. ---------------------------------------------------------------------------*/
  1155. void NetwarePerInterfacePrint( NETDIAG_PARAMS* pParams,
  1156. NETDIAG_RESULT* pResults,
  1157. INTERFACE_RESULT *pInterfaceResults)
  1158. {
  1159. // no per-interface results
  1160. }
  1161. /*!--------------------------------------------------------------------------
  1162. NetwareCleanup
  1163. -
  1164. Author: KennT
  1165. ---------------------------------------------------------------------------*/
  1166. void NetwareCleanup( NETDIAG_PARAMS* pParams, NETDIAG_RESULT* pResults)
  1167. {
  1168. Free(pResults->Netware.pszUser);
  1169. pResults->Netware.pszUser = NULL;
  1170. Free(pResults->Netware.pszServer);
  1171. pResults->Netware.pszServer = NULL;
  1172. Free(pResults->Netware.pszTree);
  1173. pResults->Netware.pszTree = NULL;
  1174. Free(pResults->Netware.pszContext);
  1175. pResults->Netware.pszContext = NULL;
  1176. MessageListCleanUp(&pResults->Netware.lmsgOutput);
  1177. }