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.

1220 lines
36 KiB

  1. /********************************************************************/
  2. /** Microsoft LAN Manager **/
  3. /** Copyright(c) Microsoft Corp., 1987-1992 **/
  4. /********************************************************************/
  5. /*
  6. * view.c
  7. * Commands for viewing what resources are available for use.
  8. *
  9. * History:
  10. * 07/02/87, ericpe, initial coding.
  11. * 10/31/88, erichn, uses OS2.H instead of DOSCALLS
  12. * 01/04/89, erichn, filenames now MAXPATHLEN LONG
  13. * 05/02/89, erichn, NLS conversion
  14. * 05/19/89, erichn, NETCMD output sorting
  15. * 06/08/89, erichn, canonicalization sweep
  16. * 02/15/91, danhi, convert to 16/32 mapping layer
  17. * 04/09/91, robdu, LM21 bug fix 1502
  18. * 07/20/92, JohnRo, Use DEFAULT_SERVER equate.
  19. */
  20. /* Include files */
  21. #define INCL_NOCOMMON
  22. #define INCL_DOSMEMMGR
  23. #define INCL_DOSFILEMGR
  24. #define INCL_ERRORS
  25. #include <os2.h>
  26. #include <search.h>
  27. #include <lmcons.h>
  28. #include <lmerr.h>
  29. #include <lmapibuf.h>
  30. #include <apperr.h>
  31. #include <apperr2.h>
  32. #include <lmshare.h>
  33. #include <lmuse.h>
  34. #include <dlserver.h>
  35. #include "mserver.h"
  36. #include "netcmds.h"
  37. #include "nettext.h"
  38. #include "msystem.h"
  39. /* Forward declarations */
  40. int __cdecl CmpSvrInfo1 ( const VOID FAR *, const VOID FAR * );
  41. int __cdecl CmpShrInfo1 ( const VOID FAR *, const VOID FAR *);
  42. int __cdecl CmpShrInfoGen ( const VOID FAR *, const VOID FAR *);
  43. DWORD get_used_as ( LPWSTR, LPWSTR, DWORD );
  44. void display_other_net(TCHAR *net, TCHAR *node) ;
  45. TCHAR * get_provider_name(TCHAR *net) ;
  46. DWORD enum_net_resource(LPNETRESOURCE, LPBYTE *, LPDWORD, LPDWORD) ;
  47. DWORD list_nets(VOID);
  48. #define VIEW_UNC 0
  49. #define VIEW_MORE (VIEW_UNC + 1)
  50. #define USE_TYPE_DISK (VIEW_MORE + 1)
  51. #define USE_TYPE_COMM (USE_TYPE_DISK + 1)
  52. #define USE_TYPE_PRINT (USE_TYPE_COMM + 1)
  53. #define USE_TYPE_IPC (USE_TYPE_PRINT + 1)
  54. #define USE_TYPE_UNKNOWN (USE_TYPE_IPC + 1)
  55. #define VIEW_CACHED_MANUAL (USE_TYPE_UNKNOWN + 1)
  56. #define VIEW_CACHED_AUTO (VIEW_CACHED_MANUAL+1)
  57. #define VIEW_CACHED_VDO (VIEW_CACHED_AUTO+1)
  58. #define VIEW_CACHED_DISABLED (VIEW_CACHED_VDO+1)
  59. static MESSAGE ViewMsgList[] = {
  60. { APE2_VIEW_UNC, NULL },
  61. { APE2_VIEW_MORE, NULL },
  62. { APE2_USE_TYPE_DISK, NULL },
  63. { APE2_USE_TYPE_COMM, NULL },
  64. { APE2_USE_TYPE_PRINT, NULL },
  65. { APE2_USE_TYPE_IPC, NULL },
  66. { APE2_GEN_UNKNOWN, NULL },
  67. { APE2_GEN_CACHED_MANUAL, NULL },
  68. { APE2_GEN_CACHED_AUTO, NULL },
  69. { APE2_GEN_CACHED_VDO, NULL },
  70. { APE2_GEN_CACHED_DISABLED, NULL },
  71. };
  72. #define NUM_VIEW_MSGS (sizeof(ViewMsgList)/sizeof(ViewMsgList[0]))
  73. #define MAX_SHARE_LEN (MAX_PATH + NNLEN + 4)
  74. /***
  75. * view_display()
  76. *
  77. * Displays info as reqested through use of the Net View command.
  78. *
  79. * Args:
  80. * name - the name of the server for which info is desired.
  81. * If NULL, the servers on the Net are enumerated.
  82. *
  83. * Returns:
  84. * nothing - success
  85. * exit(1) - command completed with errors
  86. */
  87. VOID
  88. view_display ( TCHAR * name )
  89. {
  90. DWORD dwErr;
  91. LPTSTR pEnumBuffer;
  92. LPTSTR pGetInfoBuffer;
  93. DWORD _read; /* to receive # of entries read */
  94. DWORD msgLen; /* to hold max length of messages */
  95. LPTSTR msgPtr; /* message to print */
  96. LPSERVER_INFO_1 server_entry;
  97. LPSERVER_INFO_0 server_entry_0;
  98. LPSHARE_INFO_1 share_entry;
  99. SHORT errorflag = 0;
  100. DWORD i;
  101. LPTSTR comment;
  102. LPWSTR tname = NULL;
  103. USHORT more_data = FALSE;
  104. LPTSTR DollarPtr;
  105. TCHAR *Domain = NULL;
  106. TCHAR *Network = NULL;
  107. ULONG Type = SV_TYPE_ALL;
  108. BOOLEAN b501 = TRUE;
  109. BOOLEAN bShowCache = FALSE;
  110. INT iLongestShareName = 0;
  111. INT iLongestType = 0;
  112. INT iLongestUsedAs = 0;
  113. INT iLongestCacheOrRemark = 0;
  114. #define NEXT_SHARE_ENTRY(p) \
  115. p= (b501 ? (LPSHARE_INFO_1) (((LPSHARE_INFO_501) p) + 1) : ((LPSHARE_INFO_1) p) + 1)
  116. GetMessageList(NUM_VIEW_MSGS, ViewMsgList, &msgLen);
  117. for (i = 0; SwitchList[i]; i++)
  118. {
  119. TCHAR *ptr;
  120. //
  121. // only have 2 switches, and they are not compatible
  122. //
  123. if (i > 0)
  124. {
  125. ErrorExit(APE_ConflictingSwitches);
  126. }
  127. ptr = FindColon(SwitchList[i]);
  128. if (!_tcscmp(SwitchList[i], swtxt_SW_DOMAIN))
  129. {
  130. //
  131. // If no domain specified, then we want to enumerate domains,
  132. // otherwise we want to enumerate the servers on the domain
  133. // specified.
  134. //
  135. if (ptr == NULL)
  136. Type = SV_TYPE_DOMAIN_ENUM;
  137. else
  138. Domain = ptr;
  139. }
  140. else if (!_tcscmp(SwitchList[i], swtxt_SW_NETWORK))
  141. {
  142. //
  143. // enumerate top level of specific network. if none,
  144. // default to LM.
  145. //
  146. if (ptr && *ptr)
  147. Network = ptr ;
  148. }
  149. else if( !_tcscmp(SwitchList[i], swtxt_SW_CACHE))
  150. {
  151. //
  152. // Show the cache setting for each share
  153. //
  154. bShowCache = TRUE;
  155. }
  156. else
  157. {
  158. ErrorExit(APE_InvalidSwitch);
  159. }
  160. }
  161. //
  162. // a specific net was requested. display_other_net does
  163. // not return.
  164. //
  165. if (Network != NULL)
  166. {
  167. (void) display_other_net(Network,name) ;
  168. }
  169. if (name == NULL)
  170. {
  171. ULONG i;
  172. if ((dwErr = MNetServerEnum(DEFAULT_SERVER,
  173. (Type == SV_TYPE_DOMAIN_ENUM ? 100 : 101),
  174. (LPBYTE*)&pEnumBuffer,
  175. &_read,
  176. Type,
  177. Domain)) == ERROR_MORE_DATA)
  178. {
  179. more_data = TRUE;
  180. }
  181. else if (dwErr)
  182. {
  183. ErrorExit(dwErr);
  184. }
  185. if (_read == 0)
  186. EmptyExit();
  187. qsort(pEnumBuffer,
  188. _read,
  189. (Type == SV_TYPE_DOMAIN_ENUM ? sizeof(SERVER_INFO_0) : sizeof(SERVER_INFO_1)),
  190. CmpSvrInfo1);
  191. if (Type == SV_TYPE_DOMAIN_ENUM)
  192. InfoPrint(APE2_VIEW_DOMAIN_HDR);
  193. else
  194. InfoPrint(APE2_VIEW_ALL_HDR);
  195. PrintLine();
  196. /* Print the listing */
  197. if (Type == SV_TYPE_DOMAIN_ENUM) {
  198. for (i=0, server_entry_0 =
  199. (LPSERVER_INFO_0) pEnumBuffer; i < _read;
  200. i++, server_entry_0++)
  201. {
  202. WriteToCon(TEXT("%Fws "), PaddedString(20,server_entry_0->sv0_name,NULL));
  203. PrintNL();
  204. }
  205. } else {
  206. for (i=0, server_entry =
  207. (LPSERVER_INFO_1) pEnumBuffer; i < _read;
  208. i++, server_entry++)
  209. {
  210. WriteToCon(TEXT("\\\\%Fws "), PaddedString(20,server_entry->sv1_name,NULL));
  211. PrintDependingOnLength(-56, server_entry->sv1_comment);
  212. PrintNL();
  213. }
  214. }
  215. NetApiBufferFree(pEnumBuffer);
  216. }
  217. else
  218. {
  219. DWORD avail ;
  220. DWORD totAvail;
  221. if( bShowCache == TRUE ) {
  222. dwErr = NetShareEnum(name,
  223. 501,
  224. (LPBYTE*)&pEnumBuffer,
  225. MAX_PREFERRED_LENGTH,
  226. &_read,
  227. &totAvail,
  228. NULL);
  229. }
  230. if( bShowCache == FALSE || (dwErr != NO_ERROR && dwErr != ERROR_BAD_NETPATH) ) {
  231. dwErr = NetShareEnum(name,
  232. 1,
  233. (LPBYTE*)&pEnumBuffer,
  234. MAX_PREFERRED_LENGTH,
  235. &_read,
  236. &totAvail,
  237. NULL);
  238. b501 = FALSE;
  239. }
  240. if( dwErr == ERROR_MORE_DATA )
  241. {
  242. more_data = TRUE;
  243. }
  244. else if (dwErr)
  245. {
  246. ErrorExit(dwErr);
  247. }
  248. if (_read == 0)
  249. {
  250. EmptyExit();
  251. }
  252. /* Are there any shares that we will display? */
  253. for (i=0, share_entry = (LPSHARE_INFO_1) pEnumBuffer;
  254. i < _read;
  255. i++, NEXT_SHARE_ENTRY( share_entry ) )
  256. {
  257. DollarPtr = _tcsrchr(share_entry->shi1_netname, DOLLAR);
  258. //
  259. // If no DOLLAR in sharename, or last DOLLAR is nonterminal, it is a
  260. // valid share and we want to display it. Find out the lengths of the
  261. // longest strings to display so that we can format the output in a
  262. // decent way
  263. //
  264. if (!DollarPtr || *(DollarPtr + 1))
  265. {
  266. int iTempLength = 0;
  267. //
  268. // Get the share name string that needs the most screen characters
  269. // to be displayed.
  270. //
  271. iTempLength = SizeOfHalfWidthString(share_entry->shi1_netname);
  272. if (iTempLength > iLongestShareName)
  273. {
  274. iLongestShareName = iTempLength;
  275. }
  276. //
  277. // Get the share type string that needs the most screen characters
  278. // to be displayed.
  279. //
  280. switch ( share_entry->shi1_type & ~STYPE_SPECIAL )
  281. {
  282. case STYPE_DISKTREE :
  283. iTempLength = SizeOfHalfWidthString(ViewMsgList[USE_TYPE_DISK].msg_text);
  284. break;
  285. case STYPE_PRINTQ :
  286. iTempLength = SizeOfHalfWidthString(ViewMsgList[USE_TYPE_PRINT].msg_text);
  287. break;
  288. case STYPE_DEVICE :
  289. iTempLength = SizeOfHalfWidthString(ViewMsgList[USE_TYPE_COMM].msg_text);
  290. break;
  291. case STYPE_IPC :
  292. iTempLength = SizeOfHalfWidthString(ViewMsgList[USE_TYPE_IPC].msg_text);
  293. break;
  294. default:
  295. iTempLength = SizeOfHalfWidthString(ViewMsgList[USE_TYPE_UNKNOWN].msg_text);
  296. break;
  297. }
  298. if (iTempLength > iLongestType)
  299. {
  300. iLongestType = iTempLength;
  301. }
  302. //
  303. // Get the Used As string that needs the most screen characters
  304. // to be displayed. Add 2 for a backslash and NUL character.
  305. //
  306. if (dwErr = AllocMem((wcslen(name) + wcslen(share_entry->shi1_netname) + 2) * sizeof(WCHAR),
  307. &tname))
  308. {
  309. ErrorExit(dwErr);
  310. }
  311. _tcscpy(tname, name);
  312. _tcscat(tname, TEXT("\\"));
  313. _tcscat(tname, share_entry->shi1_netname);
  314. if (!get_used_as ( tname, Buffer, LITTLE_BUF_SIZE - 1 ))
  315. {
  316. iTempLength = SizeOfHalfWidthString(Buffer);
  317. if (iTempLength > iLongestUsedAs)
  318. {
  319. iLongestUsedAs = iTempLength;
  320. }
  321. }
  322. FreeMem(tname);
  323. tname = NULL;
  324. //
  325. // Get the cache or remark string (depending on which one we
  326. // will end up displaying) that needs the most screen characters
  327. // to be displayed.
  328. //
  329. if( b501 == TRUE)
  330. {
  331. TCHAR *CacheString = NULL;
  332. switch(((LPSHARE_INFO_501) share_entry)->shi501_flags & CSC_MASK)
  333. {
  334. case CSC_CACHE_MANUAL_REINT:
  335. iTempLength = SizeOfHalfWidthString(ViewMsgList[ VIEW_CACHED_MANUAL ].msg_text);
  336. break;
  337. case CSC_CACHE_AUTO_REINT:
  338. iTempLength = SizeOfHalfWidthString(ViewMsgList[ VIEW_CACHED_AUTO ].msg_text);
  339. break;
  340. case CSC_CACHE_VDO:
  341. iTempLength = SizeOfHalfWidthString(ViewMsgList[ VIEW_CACHED_VDO ].msg_text);
  342. break;
  343. case CSC_CACHE_NONE:
  344. iTempLength = SizeOfHalfWidthString(ViewMsgList[ VIEW_CACHED_DISABLED ].msg_text);
  345. break;
  346. }
  347. }
  348. else
  349. {
  350. iTempLength = SizeOfHalfWidthString(share_entry->shi1_remark);
  351. }
  352. if (iTempLength > iLongestCacheOrRemark)
  353. {
  354. iLongestCacheOrRemark = iTempLength;
  355. }
  356. }
  357. }
  358. if (!iLongestShareName)
  359. {
  360. //
  361. // No shares to display
  362. //
  363. EmptyExit();
  364. }
  365. qsort(pEnumBuffer,
  366. _read,
  367. b501 ? sizeof(SHARE_INFO_501) : sizeof(SHARE_INFO_1),
  368. CmpShrInfo1);
  369. InfoPrintInsTxt(APE_ViewResourcesAt, name);
  370. if (dwErr = MNetServerGetInfo(name, 1, (LPBYTE*)&pGetInfoBuffer))
  371. {
  372. PrintNL();
  373. }
  374. else
  375. {
  376. server_entry = (LPSERVER_INFO_1) pGetInfoBuffer;
  377. comment = server_entry->sv1_comment;
  378. WriteToCon(TEXT("%Fws\r\n\r\n"), comment);
  379. NetApiBufferFree(pGetInfoBuffer);
  380. }
  381. //
  382. // Print the header
  383. //
  384. iLongestShareName = FindColumnWidthAndPrintHeader(iLongestShareName,
  385. APE2_VIEW_SVR_HDR_NAME,
  386. 2);
  387. iLongestType = FindColumnWidthAndPrintHeader(iLongestType,
  388. APE2_VIEW_SVR_HDR_TYPE,
  389. 2);
  390. iLongestUsedAs = FindColumnWidthAndPrintHeader(iLongestUsedAs,
  391. APE2_VIEW_SVR_HDR_USEDAS,
  392. 2);
  393. iLongestCacheOrRemark = FindColumnWidthAndPrintHeader(iLongestCacheOrRemark,
  394. APE2_VIEW_SVR_HDR_CACHEORREMARK,
  395. 2);
  396. PrintNL();
  397. //
  398. // Bail out on failure
  399. //
  400. if (iLongestShareName == -1 || iLongestType == -1 ||
  401. iLongestUsedAs == -1 || iLongestCacheOrRemark == -1)
  402. {
  403. ErrorExit(ERROR_INVALID_PARAMETER);
  404. }
  405. PrintNL();
  406. PrintLine();
  407. /* Print the listing */
  408. for (i=0, share_entry = (LPSHARE_INFO_1) pEnumBuffer;
  409. i < _read;
  410. i++, NEXT_SHARE_ENTRY(share_entry))
  411. {
  412. /* if the name end in $, do not print it */
  413. DollarPtr = _tcsrchr(share_entry->shi1_netname, DOLLAR);
  414. if (DollarPtr && *(DollarPtr + 1) == NULLC)
  415. {
  416. continue;
  417. }
  418. PrintDependingOnLength(iLongestShareName, share_entry->shi1_netname);
  419. // mask out the non type related bits
  420. switch ( share_entry->shi1_type & ~STYPE_SPECIAL )
  421. {
  422. case STYPE_DISKTREE :
  423. msgPtr = ViewMsgList[USE_TYPE_DISK].msg_text;
  424. break;
  425. case STYPE_PRINTQ :
  426. msgPtr = ViewMsgList[USE_TYPE_PRINT].msg_text;
  427. break;
  428. case STYPE_DEVICE :
  429. msgPtr = ViewMsgList[USE_TYPE_COMM].msg_text;
  430. break;
  431. case STYPE_IPC :
  432. msgPtr = ViewMsgList[USE_TYPE_IPC].msg_text;
  433. break;
  434. default:
  435. msgPtr = ViewMsgList[USE_TYPE_UNKNOWN].msg_text;
  436. break;
  437. }
  438. PrintDependingOnLength(iLongestType, msgPtr);
  439. if (dwErr = AllocMem((wcslen(name) + wcslen(share_entry->shi1_netname) + 2) * sizeof(WCHAR),
  440. &tname))
  441. {
  442. ErrorExit(dwErr);
  443. }
  444. _tcscpy(tname, name);
  445. _tcscat(tname, TEXT("\\"));
  446. _tcscat(tname, share_entry->shi1_netname);
  447. if (dwErr = get_used_as ( tname, Buffer, LITTLE_BUF_SIZE - 1 ))
  448. {
  449. errorflag = TRUE;
  450. }
  451. else
  452. {
  453. PrintDependingOnLength(iLongestUsedAs, Buffer);
  454. }
  455. FreeMem(tname);
  456. tname = NULL;
  457. //
  458. // Print out the cache settings for the share, if we're supposed to
  459. //
  460. if( b501 == TRUE )
  461. {
  462. TCHAR *CacheString = NULL;
  463. switch (((LPSHARE_INFO_501) share_entry)->shi501_flags & CSC_MASK)
  464. {
  465. case CSC_CACHE_MANUAL_REINT:
  466. CacheString = ViewMsgList[ VIEW_CACHED_MANUAL ].msg_text;
  467. break;
  468. case CSC_CACHE_AUTO_REINT:
  469. CacheString = ViewMsgList[ VIEW_CACHED_AUTO ].msg_text;
  470. break;
  471. case CSC_CACHE_VDO:
  472. CacheString = ViewMsgList[ VIEW_CACHED_VDO ].msg_text;
  473. break;
  474. case CSC_CACHE_NONE:
  475. CacheString = ViewMsgList[ VIEW_CACHED_DISABLED ].msg_text;
  476. break;
  477. }
  478. PrintDependingOnLength(iLongestCacheOrRemark, CacheString ? CacheString : TEXT(""));
  479. }
  480. else
  481. {
  482. PrintDependingOnLength(iLongestCacheOrRemark, share_entry->shi1_remark);
  483. }
  484. PrintNL();
  485. }
  486. NetApiBufferFree(pEnumBuffer);
  487. }
  488. if ( errorflag )
  489. {
  490. InfoPrint(APE_CmdComplWErrors);
  491. NetcmdExit(1);
  492. }
  493. if ( more_data )
  494. InfoPrint( APE_MoreData);
  495. else
  496. InfoSuccess();
  497. }
  498. /***
  499. * cmpsvinfo1(sva,svb)
  500. *
  501. * Compares two SERVER_INFO_1 structures and returns a relative
  502. * lexical value, suitable for using in qsort.
  503. *
  504. */
  505. int __cdecl CmpSvrInfo1(const VOID FAR * sva, const VOID FAR * svb)
  506. {
  507. return _tcsicmp(((LPSERVER_INFO_1) sva)->sv1_name,
  508. ((LPSERVER_INFO_1) svb)->sv1_name);
  509. }
  510. /***
  511. * CmpShrInfo1(share1,share2)
  512. *
  513. * Compares two SHARE_INFO_1 structures and returns a relative
  514. * lexical value, suitable for using in qsort.
  515. *
  516. */
  517. int __cdecl CmpShrInfo1(const VOID FAR * share1, const VOID FAR * share2)
  518. {
  519. return _tcsicmp(((LPSHARE_INFO_1) share1)->shi1_netname,
  520. ((LPSHARE_INFO_1) share2)->shi1_netname);
  521. }
  522. /***
  523. * CmpShrInfoGen(share1,share2)
  524. *
  525. * Compares two NETRESOURCE structures and returns a relative
  526. * lexical value, suitable for using in qsort.
  527. *
  528. */
  529. int __cdecl CmpShrInfoGen(const VOID FAR * share1, const VOID FAR * share2)
  530. {
  531. return _wcsicmp ( (*((LPNETRESOURCE *) share1))->lpRemoteName,
  532. (*((LPNETRESOURCE *) share2))->lpRemoteName );
  533. }
  534. /*
  535. * Note- get_used_as assumes the message list has been loaded.
  536. */
  537. DWORD
  538. get_used_as(
  539. LPTSTR unc,
  540. LPTSTR outbuf,
  541. DWORD cchBuf
  542. )
  543. {
  544. DWORD dwErr;
  545. DWORD cTotalAvail;
  546. LPTSTR pBuffer;
  547. LPUSE_INFO_0 pUseInfo;
  548. DWORD i;
  549. DWORD eread;
  550. BOOL fMatch = FALSE;
  551. LPTSTR tname = NULL;
  552. outbuf[0] = 0;
  553. if (dwErr = NetUseEnum(DEFAULT_SERVER, 0, (LPBYTE*)&pBuffer, MAX_PREFERRED_LENGTH,
  554. &eread, &cTotalAvail, NULL))
  555. {
  556. return dwErr;
  557. }
  558. pUseInfo = (LPUSE_INFO_0) pBuffer;
  559. for (i = 0; i < eread; i++)
  560. {
  561. if ( (!_tcsicmp(unc, pUseInfo[i].ui0_remote)))
  562. {
  563. fMatch = TRUE;
  564. }
  565. else
  566. {
  567. //
  568. // <unc> didn't match -- try \\<unc> since we allow
  569. // "net view <server>" as well as "net view \\<server>"
  570. //
  571. if (tname == NULL)
  572. {
  573. if (dwErr = AllocMem((wcslen(unc) + 3) * sizeof(WCHAR), &tname))
  574. {
  575. return dwErr;
  576. }
  577. tname[0] = tname[1] = L'\\';
  578. }
  579. wcscpy(tname + 2, unc);
  580. if ( (!_tcsicmp(tname, pUseInfo[i].ui0_remote)))
  581. {
  582. fMatch = TRUE;
  583. }
  584. }
  585. if (fMatch)
  586. {
  587. if (_tcslen(pUseInfo[i].ui0_local) > 0)
  588. {
  589. wcsncpy(outbuf, pUseInfo[i].ui0_local, cchBuf);
  590. }
  591. else
  592. {
  593. wcsncpy(outbuf, ViewMsgList[VIEW_UNC].msg_text, cchBuf);
  594. }
  595. break;
  596. }
  597. }
  598. NetApiBufferFree(pBuffer);
  599. if (tname != NULL)
  600. {
  601. FreeMem(tname);
  602. }
  603. return 0;
  604. }
  605. /*
  606. * Displays resources for another network (other than Lanman). This
  607. * function does not return.
  608. *
  609. * Args:
  610. * net - the shortname of the network we are interested in
  611. * node - the starting point of the enumeration.
  612. */
  613. void display_other_net(TCHAR *net, TCHAR *node)
  614. {
  615. LPNETRESOURCE *lplpNetResource ;
  616. NETRESOURCE NetResource ;
  617. HANDLE Handle ;
  618. BYTE TopLevelBuffer[4096] ;
  619. DWORD TopLevelBufferSize = sizeof(TopLevelBuffer) ;
  620. LPBYTE ResultBuffer ;
  621. DWORD ResultBufferSize ;
  622. DWORD i, dwErr, TopLevelCount, ResultCount = 0 ;
  623. TCHAR * ProviderName = get_provider_name(net) ;
  624. //
  625. // Check that we can get provider name and alloc the results
  626. // buffer. Netcmd normally does not free memory it allocates,
  627. // as it exits immediately.
  628. //
  629. if (!ProviderName)
  630. {
  631. DWORD dwErr = list_nets();
  632. if (dwErr != NERR_Success)
  633. {
  634. ErrorPrint(dwErr, 0);
  635. }
  636. NetcmdExit(1) ;
  637. }
  638. if (dwErr = AllocMem(ResultBufferSize = 8192, &ResultBuffer))
  639. {
  640. ErrorExit(dwErr);
  641. }
  642. if (!node)
  643. {
  644. BOOL found = FALSE ;
  645. //
  646. // no node, so must be top level. enum the top and find
  647. // matching provider.
  648. //
  649. dwErr = WNetOpenEnum(RESOURCE_GLOBALNET, 0, 0, NULL, &Handle) ;
  650. if (dwErr != WN_SUCCESS)
  651. {
  652. ErrorExit (dwErr) ;
  653. }
  654. do
  655. {
  656. TopLevelCount = 0xFFFFFFFF ;
  657. dwErr = WNetEnumResource(Handle,
  658. &TopLevelCount,
  659. TopLevelBuffer,
  660. &TopLevelBufferSize) ;
  661. if (dwErr == WN_SUCCESS || dwErr == WN_NO_MORE_ENTRIES)
  662. {
  663. LPNETRESOURCE lpNet ;
  664. DWORD i ;
  665. //
  666. // go thru looking for the right provider
  667. //
  668. lpNet = (LPNETRESOURCE) TopLevelBuffer ;
  669. for ( i = 0; i < TopLevelCount; i++, lpNet++ )
  670. {
  671. DWORD dwEnumErr ;
  672. if (!_tcsicmp(lpNet->lpProvider, ProviderName))
  673. {
  674. //
  675. // found it!
  676. //
  677. found = TRUE ;
  678. //
  679. // now go enumerate that network.
  680. //
  681. dwEnumErr = enum_net_resource(lpNet,
  682. &ResultBuffer,
  683. &ResultBufferSize,
  684. &ResultCount) ;
  685. if (dwEnumErr)
  686. {
  687. // dont report any errors here
  688. WNetCloseEnum(Handle);
  689. ErrorExit(dwEnumErr);
  690. }
  691. break ;
  692. }
  693. }
  694. }
  695. else
  696. {
  697. //
  698. // error occured.
  699. //
  700. WNetCloseEnum(Handle); // dont report any errors here
  701. ErrorExit(dwErr);
  702. }
  703. } while ((dwErr == WN_SUCCESS) && !found) ;
  704. WNetCloseEnum(Handle) ; // dont report any errors here
  705. if (!found)
  706. {
  707. ErrorExit(ERROR_BAD_PROVIDER);
  708. }
  709. }
  710. else
  711. {
  712. //
  713. // node is provided, lets start there.
  714. //
  715. NETRESOURCE NetRes ;
  716. DWORD dwEnumErr ;
  717. memset(&NetRes, 0, sizeof(NetRes)) ;
  718. NetRes.lpProvider = ProviderName ;
  719. NetRes.lpRemoteName = node ;
  720. dwEnumErr = enum_net_resource(&NetRes,
  721. &ResultBuffer,
  722. &ResultBufferSize,
  723. &ResultCount) ;
  724. if (dwEnumErr)
  725. {
  726. ErrorExit(dwEnumErr);
  727. }
  728. }
  729. if (ResultCount == 0)
  730. {
  731. EmptyExit();
  732. }
  733. //
  734. // By the time we get here, we have a buffer of pointers that
  735. // point to NETRESOURCE structures. We sort the pointers, and then
  736. // print them out.
  737. //
  738. qsort(ResultBuffer, ResultCount, sizeof(LPNETRESOURCE), CmpShrInfoGen);
  739. lplpNetResource = (LPNETRESOURCE *)ResultBuffer ;
  740. if (node)
  741. {
  742. TCHAR *TypeString ;
  743. InfoPrintInsTxt(APE_ViewResourcesAt, node);
  744. PrintLine();
  745. for (i = 0; i < ResultCount; i++, lplpNetResource++)
  746. {
  747. switch ((*lplpNetResource)->dwType)
  748. {
  749. case RESOURCETYPE_DISK:
  750. TypeString = ViewMsgList[USE_TYPE_DISK].msg_text;
  751. break ;
  752. case RESOURCETYPE_PRINT:
  753. TypeString = ViewMsgList[USE_TYPE_PRINT].msg_text;
  754. break ;
  755. default:
  756. TypeString = L"" ;
  757. break ;
  758. }
  759. WriteToCon(TEXT("%Fs %s\r\n"),
  760. PaddedString(12,TypeString,NULL),
  761. (*lplpNetResource)->lpRemoteName) ;
  762. }
  763. }
  764. else
  765. {
  766. InfoPrintInsTxt(APE2_VIEW_OTHER_HDR, ProviderName);
  767. PrintLine();
  768. for (i = 0; i < ResultCount; i++, lplpNetResource++)
  769. {
  770. WriteToCon(TEXT("%s\r\n"), (*lplpNetResource)->lpRemoteName) ;
  771. }
  772. }
  773. InfoSuccess();
  774. NetcmdExit(0);
  775. }
  776. /*
  777. * Enumerates resources for a network starting at a specific point.
  778. *
  779. * Args:
  780. * lpNetResourceStart - Where to start the enumeration
  781. * ResultBuffer - Used to return array of pointers to NETRESOURCEs.
  782. * May be reallocated as need.
  783. * ResultBufferSize - Buffer size, also used to return final size.
  784. * ResultCount - Used to return number of entries in buffer.
  785. */
  786. DWORD
  787. enum_net_resource(
  788. LPNETRESOURCE lpNetResourceStart,
  789. LPBYTE *ResultBuffer,
  790. LPDWORD ResultBufferSize,
  791. LPDWORD ResultCount
  792. )
  793. {
  794. DWORD dwErr ;
  795. HANDLE EnumHandle ;
  796. DWORD Count ;
  797. DWORD err ;
  798. LPBYTE Buffer ;
  799. DWORD BufferSize ;
  800. BOOL fDisconnect = FALSE ;
  801. LPNETRESOURCE *lpNext = (LPNETRESOURCE *)*ResultBuffer ;
  802. //
  803. // allocate memory and open the enumeration
  804. //
  805. if (err = AllocMem(BufferSize = 8192, &Buffer))
  806. {
  807. return err;
  808. }
  809. dwErr = WNetOpenEnum(RESOURCE_GLOBALNET,
  810. 0,
  811. 0,
  812. lpNetResourceStart,
  813. &EnumHandle) ;
  814. if (dwErr == ERROR_NOT_AUTHENTICATED)
  815. {
  816. //
  817. // try connecting with default credentials. we need this because
  818. // Win95 changed the behaviour of the API to fail if we are not
  819. // already logged on. below will attempt a logon with default
  820. // credentials, but will fail if that doesnt work.
  821. //
  822. dwErr = WNetAddConnection2(lpNetResourceStart, NULL, NULL, 0) ;
  823. if (dwErr == NERR_Success)
  824. {
  825. dwErr = WNetOpenEnum(RESOURCE_GLOBALNET, // redo the enum
  826. 0,
  827. 0,
  828. lpNetResourceStart,
  829. &EnumHandle) ;
  830. if (dwErr == NERR_Success)
  831. {
  832. fDisconnect = TRUE ; // remember to disconnect
  833. }
  834. else
  835. {
  836. //
  837. // disconnect now
  838. //
  839. WNetCancelConnection2(lpNetResourceStart->lpRemoteName,
  840. 0,
  841. FALSE) ;
  842. }
  843. }
  844. else
  845. {
  846. dwErr = ERROR_NOT_AUTHENTICATED ; // use original error
  847. }
  848. }
  849. if (dwErr != WN_SUCCESS)
  850. {
  851. return dwErr;
  852. }
  853. do
  854. {
  855. Count = 0xFFFFFFFF ;
  856. dwErr = WNetEnumResource(EnumHandle, &Count, Buffer, &BufferSize) ;
  857. if (((dwErr == WN_SUCCESS) || (dwErr == WN_NO_MORE_ENTRIES)) &&
  858. (Count != 0xFFFFFFFF))
  859. // NOTE - the check for FFFFFFFF is workaround for another bug in API.
  860. {
  861. LPNETRESOURCE lpNetResource ;
  862. DWORD i ;
  863. lpNetResource = (LPNETRESOURCE) Buffer ;
  864. //
  865. // stick the entries into the MyUseInfoBuffer
  866. //
  867. for ( i = 0;
  868. i < Count;
  869. i++,lpNetResource++ )
  870. {
  871. *lpNext++ = lpNetResource ;
  872. ++(*ResultCount) ;
  873. if ((LPBYTE)lpNext >= (*ResultBuffer + *ResultBufferSize))
  874. {
  875. DWORD err;
  876. *ResultBufferSize *= 2 ;
  877. if (err = ReallocMem(*ResultBufferSize,ResultBuffer))
  878. {
  879. ErrorExit(err);
  880. }
  881. lpNext = (LPNETRESOURCE *) *ResultBuffer ;
  882. lpNext += *ResultCount ;
  883. }
  884. }
  885. //
  886. // allocate a new buffer for next set, since we still need
  887. // data in the old one, we dont free it. Netcmd always lets the
  888. // system clean up when it exits.
  889. //
  890. if (dwErr == WN_SUCCESS)
  891. {
  892. if (err = AllocMem(BufferSize, &Buffer))
  893. {
  894. if (fDisconnect)
  895. {
  896. WNetCancelConnection2(lpNetResourceStart->lpRemoteName,
  897. 0,
  898. FALSE);
  899. }
  900. ErrorExit(err);
  901. }
  902. }
  903. }
  904. else
  905. {
  906. if (dwErr == WN_NO_MORE_ENTRIES)
  907. dwErr = WN_SUCCESS ;
  908. WNetCloseEnum(EnumHandle) ; // dont report any errors here
  909. if (fDisconnect)
  910. {
  911. WNetCancelConnection2(lpNetResourceStart->lpRemoteName,
  912. 0,
  913. FALSE);
  914. }
  915. return dwErr;
  916. }
  917. }
  918. while (dwErr == WN_SUCCESS);
  919. WNetCloseEnum(EnumHandle) ; // we dont report any errors here
  920. if (fDisconnect)
  921. {
  922. WNetCancelConnection2(lpNetResourceStart->lpRemoteName,
  923. 0,
  924. FALSE) ;
  925. }
  926. return NERR_Success ;
  927. }
  928. #define SHORT_NAME_KEY L"System\\CurrentControlSet\\Control\\NetworkProvider\\ShortName"
  929. /*
  930. * Given a short name for a network, find the real name (stored in registry).
  931. *
  932. * Args:
  933. * net - the short name
  934. *
  935. * Returns:
  936. * Pointer to static data containing the looked up name if successful,
  937. * NULL otherwise.
  938. */
  939. TCHAR * get_provider_name(TCHAR *net)
  940. {
  941. DWORD err ;
  942. static TCHAR buffer[256] ;
  943. HKEY hKey ;
  944. DWORD buffersize, datatype ;
  945. buffersize = sizeof(buffer) ;
  946. datatype = REG_SZ ;
  947. err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  948. SHORT_NAME_KEY,
  949. 0L,
  950. KEY_QUERY_VALUE,
  951. &hKey) ;
  952. if (err != ERROR_SUCCESS)
  953. return NULL ;
  954. err = RegQueryValueEx(hKey,
  955. net,
  956. 0L,
  957. &datatype,
  958. (LPBYTE) buffer,
  959. &buffersize) ;
  960. (void) RegCloseKey(hKey) ; // ignore any error here. its harmless
  961. // and NET.EXE doesnt hang around anyway.
  962. if (err != ERROR_SUCCESS)
  963. return(NULL) ; // treat as cannot read
  964. return ( buffer ) ;
  965. }
  966. /*
  967. * Print out the installed nets
  968. *
  969. * Args:
  970. * none
  971. *
  972. * Returns:
  973. * NERR_Success if success
  974. * error code otherwise.
  975. */
  976. DWORD
  977. list_nets(
  978. VOID
  979. )
  980. {
  981. DWORD err ;
  982. TCHAR value_name[256] ;
  983. TCHAR value_data[512] ;
  984. HKEY hKey ;
  985. BOOL fProviderFound = FALSE ;
  986. DWORD iValue, value_name_size, value_data_size ;
  987. err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  988. SHORT_NAME_KEY,
  989. 0L,
  990. KEY_QUERY_VALUE,
  991. &hKey) ;
  992. if (err != ERROR_SUCCESS)
  993. {
  994. if (err == ERROR_FILE_NOT_FOUND)
  995. {
  996. err = ERROR_BAD_PROVIDER;
  997. }
  998. return err;
  999. }
  1000. iValue = 0 ;
  1001. do {
  1002. value_name_size = sizeof(value_name)/sizeof(value_name[0]) ;
  1003. value_data_size = sizeof(value_data) ;
  1004. err = RegEnumValue(hKey,
  1005. iValue,
  1006. value_name,
  1007. &value_name_size,
  1008. NULL,
  1009. NULL,
  1010. (LPBYTE) value_data,
  1011. &value_data_size) ;
  1012. if (err == NO_ERROR)
  1013. {
  1014. if (!fProviderFound)
  1015. {
  1016. PrintNL();
  1017. InfoPrint(APE2_VIEW_OTHER_LIST) ;
  1018. fProviderFound = TRUE;
  1019. }
  1020. WriteToCon(TEXT("\t%s - %s\r\n"),value_name, value_data) ;
  1021. }
  1022. iValue++ ;
  1023. } while (err == NO_ERROR) ;
  1024. RegCloseKey(hKey) ; // ignore any error here. its harmless
  1025. // and NET.EXE doesnt hang around anyway.
  1026. if (err == ERROR_NO_MORE_ITEMS)
  1027. {
  1028. if (!fProviderFound)
  1029. {
  1030. return ERROR_BAD_PROVIDER;
  1031. }
  1032. return NO_ERROR;
  1033. }
  1034. return err;
  1035. }