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.

3066 lines
86 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. provider.c
  5. Abstract:
  6. This module contains NetWare Network Provider code. It is the
  7. client-side wrapper for APIs supported by the Workstation service.
  8. Author:
  9. Rita Wong (ritaw) 15-Feb-1993
  10. Revision History:
  11. Yi-Hsin Sung (yihsins) 10-July-1993
  12. Moved all dialog handling to nwdlg.c
  13. --*/
  14. #include <nwclient.h>
  15. #include <nwsnames.h>
  16. #include <nwcanon.h>
  17. #include <validc.h>
  18. #include <nwevent.h>
  19. #include <ntmsv1_0.h>
  20. #include <nwdlg.h>
  21. #include <nwreg.h>
  22. #include <nwauth.h>
  23. #include <mpr.h> // WNFMT_ manifests
  24. #include <nwmisc.h>
  25. #ifndef NT1057
  26. #include <nwutil.h>
  27. #endif
  28. //-------------------------------------------------------------------//
  29. // //
  30. // Local Function Prototypes //
  31. // //
  32. //-------------------------------------------------------------------//
  33. STATIC
  34. BOOL
  35. NwpWorkstationStarted(
  36. VOID
  37. );
  38. STATIC
  39. DWORD
  40. NwpMapNameToUNC(
  41. IN LPWSTR pszName,
  42. OUT LPWSTR *ppszUNC
  43. );
  44. STATIC
  45. VOID
  46. NwpGetUncInfo(
  47. IN LPWSTR lpstrUnc,
  48. OUT WORD * slashCount,
  49. OUT BOOL * isNdsUnc
  50. );
  51. STATIC
  52. LPWSTR
  53. NwpGetUncObjectName(
  54. IN LPWSTR ContainerName
  55. );
  56. //-------------------------------------------------------------------//
  57. // //
  58. // Global variables //
  59. // //
  60. //-------------------------------------------------------------------//
  61. #if DBG
  62. DWORD NwProviderTrace = 0;
  63. #endif
  64. DWORD
  65. APIENTRY
  66. NPGetCaps(
  67. IN DWORD QueryVal
  68. )
  69. /*++
  70. Routine Description:
  71. This function returns the functionality supported by this network
  72. provider.
  73. Arguments:
  74. QueryVal - Supplies a value which determines the type of information
  75. queried regarding the network provider's support in this area.
  76. Return Value:
  77. Returns a value which indicates the level of support given by this
  78. provider.
  79. --*/
  80. {
  81. #if DBG
  82. IF_DEBUG(INIT) {
  83. KdPrint(("\nNWPROVAU: NPGetCaps %lu\n", QueryVal));
  84. }
  85. #endif
  86. switch (QueryVal) {
  87. case WNNC_SPEC_VERSION:
  88. return 0x00040000;
  89. case WNNC_NET_TYPE:
  90. return WNNC_NET_NETWARE ;
  91. case WNNC_USER:
  92. return WNNC_USR_GETUSER;
  93. case WNNC_CONNECTION:
  94. return (WNNC_CON_ADDCONNECTION |
  95. WNNC_CON_ADDCONNECTION3 |
  96. WNNC_CON_CANCELCONNECTION |
  97. WNNC_CON_GETPERFORMANCE |
  98. WNNC_CON_GETCONNECTIONS);
  99. case WNNC_ENUMERATION:
  100. return ( WNNC_ENUM_GLOBAL |
  101. WNNC_ENUM_CONTEXT |
  102. WNNC_ENUM_LOCAL );
  103. case WNNC_START:
  104. if (NwpWorkstationStarted()) {
  105. return 1;
  106. }
  107. else {
  108. return 0xffffffff; // don't know
  109. }
  110. case WNNC_DIALOG:
  111. return WNNC_DLG_FORMATNETWORKNAME
  112. #ifdef NT1057
  113. ;
  114. #else
  115. | WNNC_DLG_GETRESOURCEPARENT | WNNC_DLG_GETRESOURCEINFORMATION;
  116. #endif
  117. //
  118. // The rest are not supported by the NetWare provider
  119. //
  120. default:
  121. return 0;
  122. }
  123. }
  124. #define NW_EVENT_MESSAGE_FILE L"nwevent.dll"
  125. DWORD
  126. APIENTRY
  127. NPGetUser(
  128. LPWSTR lpName,
  129. LPWSTR lpUserName,
  130. LPDWORD lpUserNameLen
  131. )
  132. /*++
  133. Routine Description:
  134. This is used to determine either the current default username, or the
  135. username used to establish a network connection.
  136. Arguments:
  137. lpName - Contains the name of the local device the caller is interested
  138. in, or a network name that the user has made a connection to. This
  139. may be NULL or the empty string if the caller is interested in the
  140. name of the user currently logged on to the system. If a network
  141. name is passed in, and the user is connected to that resource using
  142. different names, it is possible that a provider cannont resolve
  143. which username to return. In this case the provider may make an
  144. arbitrary choice amonst the possible usernames.
  145. lpUserName - Points to a buffer to receive the user name. this should
  146. be a name that can be passed into the NPAddConnection or
  147. NPAddConnection3 function to re-establish the connection with the
  148. same user name.
  149. lpBufferSize - This is used to specify the size (in characters) of the
  150. buffer passed in. If the call fails because the buffer is not big
  151. enough, this location will be used to return the required buffer size.
  152. Return Value:
  153. WN_SUCCESS - If the call is successful. Otherwise, an error code is,
  154. returned, which may include:
  155. WN_NOT_CONNECTED - lpName not a redirected device nor a connected network
  156. name.
  157. WN_MORE_DATA - The buffer is too small.
  158. WN_NO_NETWORK - Network not present.
  159. --*/
  160. {
  161. DWORD status;
  162. DWORD dwUserNameBufferSize = *lpUserNameLen * sizeof(WCHAR);
  163. DWORD CharsRequired = 0;
  164. if (lpName == NULL)
  165. {
  166. return WN_NOT_CONNECTED;
  167. }
  168. RtlZeroMemory( lpUserName, dwUserNameBufferSize );
  169. #if DBG
  170. IF_DEBUG(CONNECT)
  171. {
  172. KdPrint(("\nNWPROVAU: NPGetUser %ws\n", lpName));
  173. }
  174. #endif
  175. RpcTryExcept
  176. {
  177. status = NwrGetUser(
  178. NULL,
  179. lpName,
  180. (LPBYTE) lpUserName,
  181. dwUserNameBufferSize,
  182. &CharsRequired
  183. );
  184. if (status == WN_MORE_DATA)
  185. {
  186. //
  187. // Output buffer too small.
  188. //
  189. *lpUserNameLen = CharsRequired;
  190. }
  191. }
  192. RpcExcept(1)
  193. {
  194. status = NwpMapRpcError(RpcExceptionCode());
  195. }
  196. RpcEndExcept
  197. if (status != NO_ERROR)
  198. {
  199. SetLastError(status);
  200. }
  201. return status;
  202. }
  203. DWORD
  204. APIENTRY
  205. NPAddConnection(
  206. LPNETRESOURCEW lpNetResource,
  207. LPWSTR lpPassword,
  208. LPWSTR lpUserName
  209. )
  210. /*++
  211. Routine Description:
  212. This function creates a remote connection.
  213. Arguments:
  214. lpNetResource - Supplies the NETRESOURCE structure which specifies
  215. the local DOS device to map, the remote resource to connect to
  216. and other attributes related to the connection.
  217. lpPassword - Supplies the password to connect with.
  218. lpUserName - Supplies the username to connect with.
  219. Return Value:
  220. NO_ERROR - Successful.
  221. WN_BAD_VALUE - Invalid value specifed in lpNetResource.
  222. WN_BAD_NETNAME - Invalid remote resource name.
  223. WN_BAD_LOCALNAME - Invalid local DOS device name.
  224. WN_BAD_PASSWORD - Invalid password.
  225. WN_ALREADY_CONNECTED - Local DOS device name is already in use.
  226. Other network errors.
  227. --*/
  228. {
  229. DWORD status = NO_ERROR;
  230. LPWSTR pszRemoteName = NULL;
  231. UCHAR EncodeSeed = NW_ENCODE_SEED3;
  232. UNICODE_STRING PasswordStr;
  233. LPWSTR CachedUserName = NULL ;
  234. LPWSTR CachedPassword = NULL ;
  235. PasswordStr.Length = 0;
  236. status = NwpMapNameToUNC(
  237. lpNetResource->lpRemoteName,
  238. &pszRemoteName );
  239. if (status != NO_ERROR)
  240. {
  241. SetLastError(status);
  242. return status;
  243. }
  244. #if DBG
  245. IF_DEBUG(CONNECT) {
  246. KdPrint(("\nNWPROVAU: NPAddConnection %ws\n", pszRemoteName));
  247. }
  248. #endif
  249. RpcTryExcept
  250. {
  251. if (lpNetResource->dwType != RESOURCETYPE_ANY &&
  252. lpNetResource->dwType != RESOURCETYPE_DISK &&
  253. lpNetResource->dwType != RESOURCETYPE_PRINT)
  254. {
  255. status = WN_BAD_VALUE;
  256. }
  257. else
  258. {
  259. #ifdef NT1057
  260. //
  261. // no credentials specified, see if we have cached credentials
  262. //
  263. if (!lpPassword && !lpUserName)
  264. {
  265. (void) NwpRetrieveCachedCredentials(
  266. pszRemoteName,
  267. &CachedUserName,
  268. &CachedPassword) ;
  269. //
  270. // these values will be NULL still if nothing found
  271. //
  272. lpPassword = CachedPassword ;
  273. lpUserName = CachedUserName ;
  274. }
  275. #endif
  276. //
  277. // Encode password.
  278. //
  279. RtlInitUnicodeString(&PasswordStr, lpPassword);
  280. RtlRunEncodeUnicodeString(&EncodeSeed, &PasswordStr);
  281. status = NwrCreateConnection(
  282. NULL,
  283. lpNetResource->lpLocalName,
  284. pszRemoteName,
  285. lpNetResource->dwType,
  286. lpPassword,
  287. lpUserName
  288. );
  289. if (CachedUserName)
  290. {
  291. (void)LocalFree((HLOCAL)CachedUserName);
  292. }
  293. if (CachedPassword)
  294. {
  295. RtlZeroMemory(CachedPassword,
  296. wcslen(CachedPassword) *
  297. sizeof(WCHAR)) ;
  298. (void)LocalFree((HLOCAL)CachedPassword);
  299. }
  300. }
  301. }
  302. RpcExcept(1)
  303. {
  304. status = NwpMapRpcError(RpcExceptionCode());
  305. }
  306. RpcEndExcept
  307. if (PasswordStr.Length != 0 && !CachedPassword)
  308. {
  309. //
  310. // Restore password to original state
  311. //
  312. RtlRunDecodeUnicodeString(NW_ENCODE_SEED3, &PasswordStr);
  313. }
  314. if (status == ERROR_SHARING_PAUSED)
  315. {
  316. HMODULE MessageDll;
  317. WCHAR Buffer[1024];
  318. DWORD MessageLength;
  319. DWORD err;
  320. HKEY hkey;
  321. LPWSTR pszProviderName = NULL;
  322. //
  323. // Load the netware message file DLL
  324. //
  325. MessageDll = LoadLibraryW(NW_EVENT_MESSAGE_FILE);
  326. if (MessageDll == NULL)
  327. {
  328. goto ExitPoint ;
  329. }
  330. //
  331. // Read the Network Provider Name.
  332. //
  333. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  334. // \NWCWorkstation\networkprovider
  335. //
  336. err = RegOpenKeyExW(
  337. HKEY_LOCAL_MACHINE,
  338. NW_WORKSTATION_PROVIDER_PATH,
  339. REG_OPTION_NON_VOLATILE, // options
  340. KEY_READ, // desired access
  341. &hkey
  342. );
  343. if ( !err )
  344. {
  345. //
  346. // ignore the return code. if fail, pszProviderName is NULL
  347. //
  348. err = NwReadRegValue(
  349. hkey,
  350. NW_PROVIDER_VALUENAME,
  351. &pszProviderName // free with LocalFree
  352. );
  353. RegCloseKey( hkey );
  354. }
  355. if (err)
  356. {
  357. (void) FreeLibrary(MessageDll);
  358. goto ExitPoint ;
  359. }
  360. RtlZeroMemory(Buffer, sizeof(Buffer)) ;
  361. //
  362. // Get string from message file
  363. //
  364. MessageLength = FormatMessageW(
  365. FORMAT_MESSAGE_FROM_HMODULE,
  366. (LPVOID) MessageDll,
  367. NW_LOGIN_DISABLED,
  368. 0,
  369. Buffer,
  370. sizeof(Buffer) / sizeof(WCHAR),
  371. NULL
  372. );
  373. if (MessageLength != 0)
  374. {
  375. status = WN_EXTENDED_ERROR ;
  376. WNetSetLastErrorW(NW_LOGIN_DISABLED,
  377. Buffer,
  378. pszProviderName) ;
  379. }
  380. (void) LocalFree( (HLOCAL) pszProviderName );
  381. (void) FreeLibrary(MessageDll);
  382. }
  383. ExitPoint:
  384. if (status != NO_ERROR)
  385. {
  386. SetLastError(status);
  387. }
  388. LocalFree( (HLOCAL) pszRemoteName );
  389. return status;
  390. }
  391. DWORD
  392. APIENTRY
  393. NPAddConnection3(
  394. HWND hwndOwner,
  395. LPNETRESOURCEW lpNetResource,
  396. LPWSTR lpPassword,
  397. LPWSTR lpUserName,
  398. DWORD dwConnFlags
  399. )
  400. /*++
  401. Routine Description:
  402. This function creates a remote connection.
  403. Arguments:
  404. hwndOwner - Owner window handle for dialog boxes
  405. lpNetResource - Supplies the NETRESOURCE structure which specifies
  406. the local DOS device to map, the remote resource to connect to
  407. and other attributes related to the connection.
  408. lpPassword - Supplies the password to connect with.
  409. lpUserName - Supplies the username to connect with.
  410. dwConnFlags - CONNECT_UPDATE_PROFILE...
  411. Return Value:
  412. NO_ERROR - Successful.
  413. WN_BAD_VALUE - Invalid value specifed in lpNetResource.
  414. WN_BAD_NETNAME - Invalid remote resource name.
  415. WN_BAD_LOCALNAME - Invalid local DOS device name.
  416. WN_BAD_PASSWORD - Invalid password.
  417. WN_ALREADY_CONNECTED - Local DOS device name is already in use.
  418. Other network errors.
  419. --*/
  420. {
  421. DWORD err = NO_ERROR;
  422. LPWSTR UserName = NULL;
  423. LPWSTR Password = NULL;
  424. if ( ( dwConnFlags & CONNECT_PROMPT )
  425. && !( dwConnFlags & CONNECT_INTERACTIVE )
  426. )
  427. {
  428. return WN_BAD_VALUE;
  429. }
  430. if ( !(dwConnFlags & CONNECT_PROMPT ))
  431. {
  432. err = NPAddConnection( lpNetResource,
  433. lpPassword,
  434. lpUserName );
  435. if ( ( err == NO_ERROR )
  436. || !( dwConnFlags & CONNECT_INTERACTIVE ) // Cannot popup dialog
  437. )
  438. {
  439. return err;
  440. }
  441. }
  442. for (;;)
  443. {
  444. if ( ( err != NO_ERROR ) // CONNECT_PROMPT
  445. && ( err != WN_BAD_PASSWORD )
  446. && ( err != WN_ACCESS_DENIED )
  447. && ( err != ERROR_NO_SUCH_USER )
  448. )
  449. {
  450. // Errors not related to access problems
  451. break;
  452. }
  453. if ( UserName )
  454. {
  455. (void) LocalFree( UserName );
  456. UserName = NULL;
  457. }
  458. if ( Password )
  459. {
  460. memset( Password, 0, wcslen(Password) * sizeof(WCHAR));
  461. (void) LocalFree( Password );
  462. Password = NULL;
  463. }
  464. //
  465. // Put up dialog to get username
  466. // and password.
  467. //
  468. err = NwpGetUserCredential( hwndOwner,
  469. lpNetResource->lpRemoteName,
  470. err,
  471. lpUserName,
  472. &UserName,
  473. &Password );
  474. if ( err != NO_ERROR )
  475. break;
  476. err = NPAddConnection( lpNetResource,
  477. Password,
  478. UserName );
  479. if ( err == NO_ERROR )
  480. {
  481. #if 0
  482. if ( (UserName != NULL) && (Password != NULL))
  483. {
  484. // Checking UserName and Password is to make sure that
  485. // we have prompted for password
  486. (VOID) NwpCacheCredentials( lpNetResource->lpRemoteName,
  487. UserName,
  488. Password ) ;
  489. }
  490. #endif
  491. break;
  492. }
  493. }
  494. if ( UserName )
  495. (void) LocalFree( UserName );
  496. if ( Password )
  497. {
  498. memset( Password, 0, wcslen(Password) * sizeof(WCHAR));
  499. (void) LocalFree( Password );
  500. }
  501. return err;
  502. }
  503. DWORD
  504. APIENTRY
  505. NPCancelConnection(
  506. LPWSTR lpName,
  507. BOOL fForce
  508. )
  509. /*++
  510. Routine Description:
  511. This function deletes a remote connection.
  512. Arguments:
  513. lpName - Supplies the local DOS device, or the remote resource name
  514. if it is a UNC connection to delete.
  515. fForce - Supplies the force level to break the connection. TRUE means
  516. to forcefully delete the connection, FALSE means end the connection
  517. only if there are no opened files.
  518. Return Value:
  519. NO_ERROR - Successful.
  520. WN_BAD_NETNAME - Invalid remote resource name.
  521. WN_NOT_CONNECTED - Connection could not be found.
  522. WN_OPEN_FILES - fForce is FALSE and there are opened files on the
  523. connection.
  524. Other network errors.
  525. --*/
  526. {
  527. DWORD status = NO_ERROR;
  528. LPWSTR pszName = NULL;
  529. //
  530. // We only need to map remote resource name
  531. //
  532. if ( NwLibValidateLocalName( lpName ) != NO_ERROR )
  533. {
  534. status = NwpMapNameToUNC(
  535. lpName,
  536. &pszName
  537. );
  538. if (status != NO_ERROR) {
  539. SetLastError(status);
  540. return status;
  541. }
  542. }
  543. #if DBG
  544. IF_DEBUG(CONNECT) {
  545. KdPrint(("\nNWPROVAU: NPCancelConnection %ws, Force %u\n",
  546. pszName? pszName : lpName, fForce));
  547. }
  548. #endif
  549. RpcTryExcept {
  550. status = NwrDeleteConnection(
  551. NULL,
  552. pszName? pszName : lpName,
  553. (DWORD) fForce
  554. );
  555. }
  556. RpcExcept(1) {
  557. status = NwpMapRpcError(RpcExceptionCode());
  558. }
  559. RpcEndExcept
  560. if (status != NO_ERROR) {
  561. SetLastError(status);
  562. }
  563. LocalFree( (HLOCAL) pszName );
  564. return status;
  565. }
  566. DWORD
  567. APIENTRY
  568. NPGetConnection(
  569. LPWSTR lpLocalName,
  570. LPWSTR lpRemoteName,
  571. LPDWORD lpnBufferLen
  572. )
  573. /*++
  574. Routine Description:
  575. This function returns the remote resource name for a given local
  576. DOS device.
  577. Arguments:
  578. lpLocalName - Supplies the local DOS device to look up.
  579. lpRemoteName - Output buffer to receive the remote resource name
  580. mapped to lpLocalName.
  581. lpnBufferLen - On input, supplies length of the lpRemoteName buffer
  582. in number of characters. On output, if error returned is
  583. WN_MORE_DATA, receives the number of characters required of
  584. the output buffer to hold the output string.
  585. Return Value:
  586. NO_ERROR - Successful.
  587. WN_BAD_LOCALNAME - Invalid local DOS device.
  588. WN_NOT_CONNECTED - Connection could not be found.
  589. WN_MORE_DATA - Output buffer is too small.
  590. Other network errors.
  591. --*/
  592. {
  593. DWORD status = NO_ERROR;
  594. DWORD CharsRequired;
  595. #if DBG
  596. IF_DEBUG(CONNECT) {
  597. KdPrint(("\nNWPROVAU: NPGetConnection %ws\n", lpLocalName));
  598. }
  599. #endif
  600. RpcTryExcept {
  601. if (lpRemoteName && *lpnBufferLen)
  602. *lpRemoteName = 0 ;
  603. status = NwrQueryServerResource(
  604. NULL,
  605. lpLocalName,
  606. (*lpnBufferLen == 0? NULL : lpRemoteName),
  607. *lpnBufferLen,
  608. &CharsRequired
  609. );
  610. if (status == ERROR_INSUFFICIENT_BUFFER)
  611. status = WN_MORE_DATA;
  612. if (status == WN_MORE_DATA) {
  613. *lpnBufferLen = CharsRequired;
  614. }
  615. }
  616. RpcExcept(1) {
  617. status = NwpMapRpcError(RpcExceptionCode());
  618. }
  619. RpcEndExcept
  620. if (status != NO_ERROR) {
  621. SetLastError(status);
  622. }
  623. #if DBG
  624. IF_DEBUG(CONNECT) {
  625. KdPrint(("\nNWPROVAU: NPGetConnection returns %lu\n", status));
  626. if (status == NO_ERROR) {
  627. KdPrint((" %ws, BufferLen %lu, CharsRequired %lu\n", lpRemoteName, *lpnBufferLen, CharsRequired));
  628. }
  629. }
  630. #endif
  631. return status;
  632. }
  633. DWORD
  634. APIENTRY
  635. NPGetConnectionPerformance(
  636. LPCWSTR lpRemoteName,
  637. LPNETCONNECTINFOSTRUCT lpNetConnectInfo
  638. )
  639. /*++
  640. Routine Description:
  641. This function returns information about the expected performance of a
  642. connection used to access a network resource. The request can only be
  643. for a network resource to which there is currently a connection.
  644. Arguments:
  645. lpRemoteName - Contains the local name or remote name for a resource
  646. for which a connection exists.
  647. lpNetConnectInfo - This is a pointer to a NETCONNECTINFOSTRUCT structure
  648. which is to be filled if the connection performance
  649. of connection lpRemoteName can be determined.
  650. Return Value:
  651. NO_ERROR - Successful.
  652. WN_NOT_CONNECTED - Connection could not be found.
  653. WN_NONETWORK - Network is not present.
  654. Other network errors.
  655. --*/
  656. {
  657. DWORD status = NO_ERROR;
  658. LPWSTR pszRemoteName;
  659. if ( lpNetConnectInfo == NULL )
  660. {
  661. status = ERROR_INVALID_PARAMETER;
  662. SetLastError(status);
  663. return status;
  664. }
  665. pszRemoteName = (LPWSTR) LocalAlloc( LMEM_ZEROINIT,
  666. ( wcslen(lpRemoteName) + 1 ) *
  667. sizeof(WCHAR) );
  668. if ( pszRemoteName == NULL )
  669. {
  670. status = ERROR_NOT_ENOUGH_MEMORY;
  671. SetLastError(status);
  672. return status;
  673. }
  674. wcscpy( pszRemoteName, lpRemoteName );
  675. _wcsupr( pszRemoteName );
  676. #if DBG
  677. IF_DEBUG(CONNECT) {
  678. KdPrint(("\nNWPROVAU: NPGetConnectionPerformance %ws\n", pszRemoteName));
  679. }
  680. #endif
  681. RpcTryExcept {
  682. status = NwrGetConnectionPerformance(
  683. NULL,
  684. pszRemoteName,
  685. (LPBYTE) lpNetConnectInfo,
  686. sizeof(NETCONNECTINFOSTRUCT) );
  687. }
  688. RpcExcept(1)
  689. {
  690. status = NwpMapRpcError(RpcExceptionCode());
  691. }
  692. RpcEndExcept
  693. if (status != NO_ERROR)
  694. {
  695. SetLastError(status);
  696. }
  697. LocalFree( (HLOCAL) pszRemoteName );
  698. return status;
  699. }
  700. DWORD
  701. APIENTRY
  702. NPGetUniversalName(
  703. #ifdef NT1057
  704. LPWSTR lpLocalPath,
  705. #else
  706. LPCWSTR lpLocalPath,
  707. #endif
  708. DWORD dwInfoLevel,
  709. LPVOID lpBuffer,
  710. LPDWORD lpBufferSize
  711. )
  712. /*++
  713. Routine Description:
  714. This function returns the universal resource name for a given local
  715. path.
  716. Arguments:
  717. lpLocalPath - Supplies the local DOS Path to look up.
  718. dwInfoLevel - Info level requested.
  719. lpBuffer - Output buffer to receive the appropruatye structure.
  720. lpBufferLen - On input, supplies length of the buffer in number of
  721. bytes. On output, if error returned is WN_MORE_DATA, receives
  722. the number of bytes required of the output buffer.
  723. Return Value:
  724. NO_ERROR - Successful.
  725. WN_BAD_LOCALNAME - Invalid local DOS device.
  726. WN_NOT_CONNECTED - Connection could not be found.
  727. WN_MORE_DATA - Output buffer is too small.
  728. Other network errors.
  729. --*/
  730. {
  731. DWORD status = NO_ERROR;
  732. DWORD dwCharsRequired = MAX_PATH + 1 ;
  733. DWORD dwBytesNeeded ;
  734. DWORD dwLocalLength ;
  735. LPWSTR lpRemoteBuffer ;
  736. WCHAR szDrive[3] ;
  737. //
  738. // check for bad info level
  739. //
  740. if ((dwInfoLevel != UNIVERSAL_NAME_INFO_LEVEL) &&
  741. (dwInfoLevel != REMOTE_NAME_INFO_LEVEL))
  742. {
  743. return WN_BAD_VALUE ;
  744. }
  745. //
  746. // check for bad pointers
  747. //
  748. if (!lpLocalPath || !lpBuffer || !lpBufferSize)
  749. {
  750. return WN_BAD_POINTER ;
  751. }
  752. //
  753. // local path must at least have "X:"
  754. //
  755. if (((dwLocalLength = wcslen(lpLocalPath)) < 2) ||
  756. (lpLocalPath[1] != L':') ||
  757. ((dwLocalLength > 2) && (lpLocalPath[2] != L'\\')))
  758. {
  759. return WN_BAD_VALUE ;
  760. }
  761. //
  762. // preallocate some memory
  763. //
  764. if (!(lpRemoteBuffer = (LPWSTR) LocalAlloc(
  765. LPTR,
  766. dwCharsRequired * sizeof(WCHAR))))
  767. {
  768. status = GetLastError() ;
  769. goto ErrorExit ;
  770. }
  771. szDrive[2] = 0 ;
  772. wcsncpy(szDrive, lpLocalPath, 2) ;
  773. //
  774. // get the remote path by calling the existing API
  775. //
  776. status = NPGetConnection(
  777. szDrive,
  778. lpRemoteBuffer,
  779. &dwCharsRequired) ;
  780. if (status == WN_MORE_DATA)
  781. {
  782. //
  783. // reallocate the correct size
  784. //
  785. if (!(lpRemoteBuffer = (LPWSTR) LocalReAlloc(
  786. (HLOCAL) lpRemoteBuffer,
  787. dwCharsRequired * sizeof(WCHAR),
  788. LMEM_MOVEABLE)))
  789. {
  790. status = GetLastError() ;
  791. goto ErrorExit ;
  792. }
  793. status = NPGetConnection(
  794. szDrive,
  795. lpRemoteBuffer,
  796. &dwCharsRequired) ;
  797. }
  798. if (status != WN_SUCCESS)
  799. {
  800. goto ErrorExit ;
  801. }
  802. //
  803. // at minimum we will need this size of the UNC name
  804. // the -2 is because we loose the drive letter & colon.
  805. //
  806. dwBytesNeeded = (wcslen(lpRemoteBuffer) +
  807. dwLocalLength - 2 + 1) * sizeof(WCHAR) ;
  808. switch (dwInfoLevel)
  809. {
  810. case UNIVERSAL_NAME_INFO_LEVEL:
  811. {
  812. LPUNIVERSAL_NAME_INFO lpUniversalNameInfo ;
  813. //
  814. // calculate how many bytes we really need
  815. //
  816. dwBytesNeeded += sizeof(UNIVERSAL_NAME_INFO) ;
  817. if (*lpBufferSize < dwBytesNeeded)
  818. {
  819. *lpBufferSize = dwBytesNeeded ;
  820. status = WN_MORE_DATA ;
  821. break ;
  822. }
  823. //
  824. // now we are all set. just stick the data in the buffer
  825. //
  826. lpUniversalNameInfo = (LPUNIVERSAL_NAME_INFO) lpBuffer ;
  827. lpUniversalNameInfo->lpUniversalName = (LPWSTR)
  828. (((LPBYTE)lpBuffer) + sizeof(UNIVERSAL_NAME_INFO)) ;
  829. wcscpy(lpUniversalNameInfo->lpUniversalName,
  830. lpRemoteBuffer) ;
  831. wcscat(lpUniversalNameInfo->lpUniversalName,
  832. lpLocalPath+2) ;
  833. break ;
  834. }
  835. case REMOTE_NAME_INFO_LEVEL :
  836. {
  837. LPREMOTE_NAME_INFO lpRemoteNameInfo ;
  838. //
  839. // calculate how many bytes we really need
  840. //
  841. dwBytesNeeded *= 2 ; // essentially twice the info + terminator
  842. dwBytesNeeded += (sizeof(REMOTE_NAME_INFO) + sizeof(WCHAR)) ;
  843. if (*lpBufferSize < dwBytesNeeded)
  844. {
  845. *lpBufferSize = dwBytesNeeded ;
  846. status = WN_MORE_DATA ;
  847. break ;
  848. }
  849. //
  850. // now we are all set. just stick the data in the buffer
  851. //
  852. lpRemoteNameInfo = (LPREMOTE_NAME_INFO) lpBuffer ;
  853. lpRemoteNameInfo->lpUniversalName = (LPWSTR)
  854. (((LPBYTE)lpBuffer) + sizeof(REMOTE_NAME_INFO)) ;
  855. wcscpy(lpRemoteNameInfo->lpUniversalName,
  856. lpRemoteBuffer) ;
  857. wcscat(lpRemoteNameInfo->lpUniversalName,
  858. lpLocalPath+2) ;
  859. lpRemoteNameInfo->lpConnectionName =
  860. lpRemoteNameInfo->lpUniversalName +
  861. wcslen(lpRemoteNameInfo->lpUniversalName) + 1 ;
  862. wcscpy(lpRemoteNameInfo->lpConnectionName,
  863. lpRemoteBuffer) ;
  864. lpRemoteNameInfo->lpRemainingPath =
  865. lpRemoteNameInfo->lpConnectionName +
  866. wcslen(lpRemoteNameInfo->lpConnectionName) + 1 ;
  867. wcscpy(lpRemoteNameInfo->lpRemainingPath,
  868. lpLocalPath+2) ;
  869. break ;
  870. }
  871. default:
  872. //
  873. // yikes!
  874. //
  875. status = WN_BAD_VALUE ;
  876. ASSERT(FALSE);
  877. }
  878. ErrorExit:
  879. if (lpRemoteBuffer)
  880. {
  881. (void) LocalFree((HLOCAL)lpRemoteBuffer) ;
  882. }
  883. return status;
  884. }
  885. DWORD
  886. APIENTRY
  887. NPOpenEnum(
  888. DWORD dwScope,
  889. DWORD dwType,
  890. DWORD dwUsage,
  891. LPNETRESOURCEW lpNetResource,
  892. LPHANDLE lphEnum
  893. )
  894. /*++
  895. Routine Description:
  896. This function initiates an enumeration of either connections, or
  897. browsing of network resource.
  898. Arguments:
  899. dwScope - Supplies the category of enumeration to do--either
  900. connection or network browsing.
  901. dwType - Supplies the type of resource to get--either disk,
  902. print, or it does not matter.
  903. dwUsage - Supplies the object type to get--either container,
  904. or connectable usage.
  905. lpNetResource - Supplies, in the lpRemoteName field, the container
  906. name to enumerate under.
  907. lphEnum - Receives the resumable context handle to be used on all
  908. subsequent calls to get the list of objects under the container.
  909. Return Value:
  910. NO_ERROR - Successful.
  911. WN_BAD_VALUE - Either the dwScope, dwType, or the dwUsage specified
  912. is not acceptable.
  913. WN_BAD_NETNAME - Invalid remote resource name.
  914. WN_NOT_CONTAINER - Remote resource name is not a container.
  915. Other network errors.
  916. --*/
  917. {
  918. DWORD status = NO_ERROR;
  919. #if DBG
  920. IF_DEBUG(ENUM)
  921. {
  922. KdPrint(("\nNWPROVAU: NPOpenEnum\n"));
  923. }
  924. #endif
  925. RpcTryExcept
  926. {
  927. if ( ( dwType & RESOURCETYPE_DISK ) ||
  928. ( dwType & RESOURCETYPE_PRINT ) ||
  929. ( dwType == RESOURCETYPE_ANY ) )
  930. {
  931. switch ( dwScope )
  932. {
  933. case RESOURCE_CONNECTED:
  934. status = NwrOpenEnumConnections( NULL,
  935. dwType,
  936. (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
  937. break;
  938. case RESOURCE_CONTEXT:
  939. status = NwrOpenEnumContextInfo( NULL,
  940. dwType,
  941. (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
  942. break;
  943. case RESOURCE_GLOBALNET:
  944. if ( lpNetResource == NULL )
  945. {
  946. //
  947. // Enumerating servers and NDS trees
  948. //
  949. if ( dwUsage & RESOURCEUSAGE_CONTAINER || dwUsage == 0 )
  950. {
  951. status = NwrOpenEnumServersAndNdsTrees( NULL,
  952. (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
  953. }
  954. else
  955. {
  956. //
  957. // There is no such thing as a connectable server
  958. // object.
  959. //
  960. status = WN_BAD_VALUE;
  961. }
  962. }
  963. else
  964. {
  965. BOOL IsEnumVolumes = TRUE;
  966. LPWSTR pszRemoteName = NULL;
  967. WORD slashCount;
  968. BOOL isNdsUnc;
  969. NwpGetUncInfo( lpNetResource->lpRemoteName,
  970. &slashCount,
  971. &isNdsUnc );
  972. //
  973. // Either enumerating volumes, directories, or NDS subtrees
  974. //
  975. if ( dwUsage & RESOURCEUSAGE_CONNECTABLE ||
  976. dwUsage & RESOURCEUSAGE_CONTAINER ||
  977. dwUsage == 0 )
  978. {
  979. LPWSTR tempStrPtr = lpNetResource->lpRemoteName;
  980. DWORD dwClassType = 0;
  981. //
  982. // Get rid of the <space> if a NDS tree name ...
  983. //
  984. if ( tempStrPtr[0] == L' ' &&
  985. tempStrPtr[1] == L'\\' &&
  986. tempStrPtr[2] == L'\\' )
  987. tempStrPtr = &tempStrPtr[1];
  988. if ( lpNetResource->dwDisplayType == RESOURCEDISPLAYTYPE_TREE )
  989. {
  990. if ( ( dwType == RESOURCETYPE_ANY ) ||
  991. ( ( dwType & RESOURCETYPE_DISK ) &&
  992. ( dwType & RESOURCETYPE_PRINT ) ) )
  993. {
  994. status = NwrOpenEnumNdsSubTrees_Any( NULL,
  995. tempStrPtr,
  996. NULL,
  997. (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
  998. }
  999. else if ( dwType & RESOURCETYPE_DISK )
  1000. {
  1001. status = NwrOpenEnumNdsSubTrees_Disk( NULL,
  1002. tempStrPtr,
  1003. NULL,
  1004. (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
  1005. }
  1006. else if ( dwType & RESOURCETYPE_PRINT )
  1007. {
  1008. status = NwrOpenEnumNdsSubTrees_Print( NULL,
  1009. tempStrPtr,
  1010. NULL,
  1011. (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
  1012. }
  1013. else
  1014. {
  1015. KdPrint(("NWOpenEnum: Unhandled dwType %lu\n", dwType));
  1016. }
  1017. }
  1018. else if (
  1019. ( slashCount < 4 ) &&
  1020. ( ( dwType == RESOURCETYPE_ANY ) ||
  1021. ( ( dwType & RESOURCETYPE_DISK ) &&
  1022. ( dwType & RESOURCETYPE_PRINT ) ) ) &&
  1023. ( ( status = NwrOpenEnumNdsSubTrees_Any( NULL,
  1024. tempStrPtr,
  1025. &dwClassType,
  1026. (LPNWWKSTA_CONTEXT_HANDLE) lphEnum ) )
  1027. ==NO_ERROR )
  1028. )
  1029. {
  1030. status = NO_ERROR;
  1031. }
  1032. else if (
  1033. ( slashCount < 4 ) &&
  1034. ( dwType & RESOURCETYPE_DISK ) &&
  1035. ( ( status = NwrOpenEnumNdsSubTrees_Disk( NULL,
  1036. tempStrPtr,
  1037. &dwClassType,
  1038. (LPNWWKSTA_CONTEXT_HANDLE) lphEnum ) )
  1039. ==NO_ERROR )
  1040. )
  1041. {
  1042. status = NO_ERROR;
  1043. }
  1044. else if (
  1045. ( slashCount < 4 ) &&
  1046. ( dwType & RESOURCETYPE_PRINT ) &&
  1047. ( ( status = NwrOpenEnumNdsSubTrees_Print( NULL,
  1048. tempStrPtr,
  1049. &dwClassType,
  1050. (LPNWWKSTA_CONTEXT_HANDLE) lphEnum ) )
  1051. ==NO_ERROR )
  1052. )
  1053. {
  1054. status = NO_ERROR;
  1055. }
  1056. else if (
  1057. (slashCount < 4
  1058. &&
  1059. (status == ERROR_NETWORK_ACCESS_DENIED
  1060. ||
  1061. status == ERROR_GEN_FAILURE
  1062. ||
  1063. status == ERROR_ACCESS_DENIED
  1064. ||
  1065. status == ERROR_BAD_NETPATH
  1066. ||
  1067. status == WN_BAD_NETNAME
  1068. ||
  1069. status == ERROR_INVALID_NAME))
  1070. ||
  1071. ( slashCount > 3 && status == NO_ERROR )
  1072. )
  1073. {
  1074. if (( status == ERROR_NETWORK_ACCESS_DENIED ) &&
  1075. ( dwClassType == CLASS_TYPE_NCP_SERVER ))
  1076. {
  1077. status = NO_ERROR;
  1078. isNdsUnc = TRUE;
  1079. IsEnumVolumes = TRUE;
  1080. }
  1081. else if ( ( status == ERROR_NETWORK_ACCESS_DENIED ) &&
  1082. ( ( dwClassType == CLASS_TYPE_VOLUME ) ||
  1083. ( dwClassType == CLASS_TYPE_DIRECTORY_MAP ) ) )
  1084. {
  1085. status = NO_ERROR;
  1086. isNdsUnc = TRUE;
  1087. IsEnumVolumes = FALSE;
  1088. }
  1089. else
  1090. {
  1091. //
  1092. // A third backslash means that we want to
  1093. // enumerate the directories.
  1094. //
  1095. if ( isNdsUnc && slashCount > 3 )
  1096. IsEnumVolumes = FALSE;
  1097. if ( !isNdsUnc && slashCount > 2 )
  1098. IsEnumVolumes = FALSE;
  1099. if ( lpNetResource->dwDisplayType == RESOURCEDISPLAYTYPE_SHARE )
  1100. IsEnumVolumes = FALSE;
  1101. }
  1102. status = NwpMapNameToUNC( tempStrPtr,
  1103. &pszRemoteName );
  1104. if ( status == NO_ERROR )
  1105. {
  1106. if ( IsEnumVolumes )
  1107. {
  1108. LPWSTR pszServerName = pszRemoteName;
  1109. // The following 10 lines are a hack to
  1110. // allow the provider to browse past the CN=<server>
  1111. // object in an NDS tree.
  1112. if ( slashCount == 3 && isNdsUnc == TRUE )
  1113. {
  1114. pszServerName = (LPWSTR)
  1115. NwpGetUncObjectName( pszRemoteName );
  1116. if ( pszServerName == NULL )
  1117. pszServerName = pszRemoteName;
  1118. }
  1119. else if ( dwUsage & RESOURCEUSAGE_ATTACHED )
  1120. {
  1121. #ifndef NT1057
  1122. // This is a bindery server.
  1123. // Return WN_NOT_AUTHENTICATED if
  1124. // we are not already attached so
  1125. // that clients ( explorer ) will
  1126. // do NPAddConnection3 to make
  1127. // a connection to the server.
  1128. BOOL fAttached;
  1129. BOOL fAuthenticated;
  1130. status = NwIsServerOrTreeAttached(
  1131. pszServerName + 2,
  1132. &fAttached,
  1133. &fAuthenticated );
  1134. if ( status != NO_ERROR )
  1135. break;
  1136. if ( !fAttached || !fAuthenticated)
  1137. {
  1138. // See if the server belongs to
  1139. // our provider.
  1140. status = NwrOpenEnumVolumes(
  1141. NULL,
  1142. pszServerName,
  1143. (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
  1144. if ( status == NO_ERROR )
  1145. {
  1146. // The server belongs to us.
  1147. // Close the handle and
  1148. // return not attached if
  1149. // callee passed in dwUsage
  1150. // flag:
  1151. // RESOURCEUSAGE_ATTACHED.
  1152. // Note: handle will be null
  1153. // after return from
  1154. // NwrCloseEnum
  1155. NwrCloseEnum( (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
  1156. status = WN_NOT_AUTHENTICATED;
  1157. }
  1158. else
  1159. {
  1160. // else the server does not
  1161. // belong to us.
  1162. status = WN_BAD_NETNAME;
  1163. }
  1164. break;
  1165. }
  1166. #endif
  1167. } // else, this is a bindery server and
  1168. // client does not care whether we
  1169. // are bindery authenticated.
  1170. if ( ( dwType == RESOURCETYPE_ANY ) ||
  1171. ( ( dwType & RESOURCETYPE_DISK ) &&
  1172. ( dwType & RESOURCETYPE_PRINT ) ) )
  1173. {
  1174. status = NwrOpenEnumVolumesQueues(
  1175. NULL,
  1176. pszServerName,
  1177. (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
  1178. }
  1179. else if ( dwType & RESOURCETYPE_DISK )
  1180. {
  1181. status = NwrOpenEnumVolumes(
  1182. NULL,
  1183. pszServerName,
  1184. (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
  1185. }
  1186. else if ( dwType & RESOURCETYPE_PRINT )
  1187. {
  1188. status = NwrOpenEnumQueues(
  1189. NULL,
  1190. pszServerName,
  1191. (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
  1192. }
  1193. }
  1194. else
  1195. {
  1196. LPWSTR CachedUserName = NULL ;
  1197. LPWSTR CachedPassword = NULL ;
  1198. #ifdef NT1057 // Make OpenEnum not interactive on SUR
  1199. (void) NwpRetrieveCachedCredentials( pszRemoteName,
  1200. &CachedUserName,
  1201. &CachedPassword );
  1202. #endif
  1203. status = NwrOpenEnumDirectories(
  1204. NULL,
  1205. pszRemoteName,
  1206. CachedUserName,
  1207. CachedPassword,
  1208. (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
  1209. #ifndef NT1057 // Make OpenEnum not interactive on SUR
  1210. if ( (status == ERROR_INVALID_PASSWORD)
  1211. || (status == ERROR_NO_SUCH_USER )
  1212. )
  1213. {
  1214. status = WN_NOT_AUTHENTICATED;
  1215. break;
  1216. }
  1217. #else
  1218. if ( CachedUserName )
  1219. {
  1220. (void) LocalFree( (HLOCAL) CachedUserName );
  1221. }
  1222. if ( CachedPassword )
  1223. {
  1224. RtlZeroMemory( CachedPassword,
  1225. wcslen(CachedPassword) *
  1226. sizeof( WCHAR ) );
  1227. (void) LocalFree( ( HLOCAL ) CachedPassword );
  1228. }
  1229. if ( ( status == ERROR_INVALID_PASSWORD ) ||
  1230. ( status == ERROR_NO_SUCH_USER ) )
  1231. {
  1232. LPWSTR UserName;
  1233. LPWSTR Password;
  1234. LPWSTR TmpPtr;
  1235. //
  1236. // Put up dialog to get username
  1237. // and password.
  1238. //
  1239. status = NwpGetUserCredential( NULL,
  1240. tempStrPtr,
  1241. status,
  1242. NULL,
  1243. &UserName,
  1244. &Password);
  1245. if ( status == NO_ERROR )
  1246. {
  1247. status = NwrOpenEnumDirectories(
  1248. NULL,
  1249. pszRemoteName,
  1250. UserName,
  1251. Password,
  1252. (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
  1253. if ( status == NO_ERROR )
  1254. {
  1255. status = NwpCacheCredentials(
  1256. pszRemoteName,
  1257. UserName,
  1258. Password ) ;
  1259. }
  1260. (void) LocalFree( UserName );
  1261. //
  1262. // Clear the password
  1263. //
  1264. TmpPtr = Password;
  1265. while ( *TmpPtr != 0 )
  1266. *TmpPtr++ = 0;
  1267. (void) LocalFree( Password );
  1268. }
  1269. else if ( status == ERROR_WINDOW_NOT_DIALOG )
  1270. {
  1271. //
  1272. // Caller is not a GUI app.
  1273. //
  1274. status = ERROR_INVALID_PASSWORD;
  1275. }
  1276. else if ( status == WN_CANCEL )
  1277. {
  1278. //
  1279. // Cancel was pressed but we still
  1280. // have to return success or MPR
  1281. // will popup the error. Return
  1282. // a bogus enum handle.
  1283. //
  1284. *lphEnum = (HANDLE) 0xFFFFFFFF;
  1285. status = NO_ERROR;
  1286. }
  1287. }
  1288. #endif
  1289. }
  1290. }
  1291. else
  1292. {
  1293. status = WN_BAD_NETNAME;
  1294. }
  1295. }
  1296. }
  1297. else
  1298. {
  1299. status = WN_BAD_VALUE;
  1300. }
  1301. if ( pszRemoteName != NULL )
  1302. LocalFree( (HLOCAL) pszRemoteName );
  1303. }
  1304. break;
  1305. default:
  1306. KdPrint(("NWPROVIDER: Invalid dwScope %lu\n", dwScope));
  1307. status = WN_BAD_VALUE;
  1308. } // end switch
  1309. }
  1310. else
  1311. {
  1312. status = WN_BAD_VALUE;
  1313. }
  1314. }
  1315. RpcExcept( 1 )
  1316. {
  1317. status = NwpMapRpcError(RpcExceptionCode());
  1318. }
  1319. RpcEndExcept
  1320. if ( status == ERROR_FILE_NOT_FOUND )
  1321. status = WN_BAD_NETNAME;
  1322. if ( status != NO_ERROR )
  1323. {
  1324. SetLastError( status );
  1325. }
  1326. return status;
  1327. }
  1328. DWORD
  1329. APIENTRY
  1330. NPEnumResource(
  1331. HANDLE hEnum,
  1332. LPDWORD lpcCount,
  1333. LPVOID lpBuffer,
  1334. LPDWORD lpBufferSize
  1335. )
  1336. /*++
  1337. Routine Description:
  1338. This function returns a lists of objects within the container
  1339. specified by the enumeration context handle.
  1340. Arguments:
  1341. hEnum - Supplies the resumable enumeration context handle.
  1342. NOTE: If this value is 0xFFFFFFFF, it is not a context
  1343. handle and this routine is required to return
  1344. WN_NO_MORE_ENTRIES. This hack is to handle the
  1345. case where the user cancelled out of the network
  1346. credential dialog on NwrOpenEnumDirectories and we
  1347. cannot return an error there or we generate an error
  1348. popup.
  1349. lpcCount - On input, supplies the number of entries to get.
  1350. On output, if NO_ERROR is returned, receives the number
  1351. of entries NETRESOURCE returned in lpBuffer.
  1352. lpBuffer - Receives an array of NETRESOURCE entries, each
  1353. entry describes an object within the container.
  1354. lpBufferSize - On input, supplies the size of lpBuffer in
  1355. bytes. On output, if WN_MORE_DATA is returned, receives
  1356. the number of bytes needed in the buffer to get the
  1357. next entry.
  1358. Return Value:
  1359. NO_ERROR - Successfully returned at least one entry.
  1360. WN_NO_MORE_ENTRIES - Reached the end of enumeration and nothing
  1361. is returned.
  1362. WN_MORE_DATA - lpBuffer is too small to even get one entry.
  1363. WN_BAD_HANDLE - The enumeration handle is invalid.
  1364. Other network errors.
  1365. --*/
  1366. {
  1367. DWORD status = NO_ERROR;
  1368. DWORD BytesNeeded = 0;
  1369. DWORD EntriesRead = 0;
  1370. #if DBG
  1371. IF_DEBUG(ENUM) {
  1372. KdPrint(("\nNWPROVAU: NPEnumResource\n"));
  1373. }
  1374. #endif
  1375. RpcTryExcept {
  1376. if (hEnum == (HANDLE) 0xFFFFFFFF) {
  1377. status = WN_NO_MORE_ENTRIES;
  1378. goto EndOfTry;
  1379. }
  1380. status = NwrEnum(
  1381. (NWWKSTA_CONTEXT_HANDLE) hEnum,
  1382. *lpcCount,
  1383. (LPBYTE) lpBuffer,
  1384. *lpBufferSize,
  1385. &BytesNeeded,
  1386. &EntriesRead
  1387. );
  1388. if (status == WN_MORE_DATA) {
  1389. //
  1390. // Output buffer too small to fit a single entry.
  1391. //
  1392. *lpBufferSize = BytesNeeded;
  1393. }
  1394. else if (status == NO_ERROR) {
  1395. *lpcCount = EntriesRead;
  1396. }
  1397. EndOfTry: ;
  1398. }
  1399. RpcExcept(1) {
  1400. status = NwpMapRpcError(RpcExceptionCode());
  1401. }
  1402. RpcEndExcept
  1403. if (status != NO_ERROR && status != WN_NO_MORE_ENTRIES) {
  1404. SetLastError(status);
  1405. }
  1406. else
  1407. {
  1408. //
  1409. // Convert offsets of strings to pointers
  1410. //
  1411. if (EntriesRead > 0) {
  1412. DWORD i;
  1413. LPNETRESOURCEW NetR;
  1414. NetR = lpBuffer;
  1415. for (i = 0; i < EntriesRead; i++, NetR++) {
  1416. if (NetR->lpLocalName != NULL) {
  1417. NetR->lpLocalName = (LPWSTR) ((DWORD_PTR) lpBuffer +
  1418. (DWORD_PTR) NetR->lpLocalName);
  1419. }
  1420. NetR->lpRemoteName = (LPWSTR) ((DWORD_PTR) lpBuffer +
  1421. (DWORD_PTR) NetR->lpRemoteName);
  1422. if (NetR->lpComment != NULL) {
  1423. NetR->lpComment = (LPWSTR) ((DWORD_PTR) lpBuffer +
  1424. (DWORD_PTR) NetR->lpComment);
  1425. }
  1426. if (NetR->lpProvider != NULL) {
  1427. NetR->lpProvider = (LPWSTR) ((DWORD_PTR) lpBuffer +
  1428. (DWORD_PTR) NetR->lpProvider);
  1429. }
  1430. }
  1431. }
  1432. }
  1433. return status;
  1434. }
  1435. DWORD
  1436. APIENTRY
  1437. NPGetResourceInformation(
  1438. LPNETRESOURCEW lpNetResource,
  1439. LPVOID lpBuffer,
  1440. LPDWORD cbBuffer,
  1441. LPWSTR * lplpSystem
  1442. )
  1443. /*++
  1444. Routine Description:
  1445. This function returns an object which details information
  1446. about a specified network resource.
  1447. Arguments:
  1448. lpNetResource - This specifies the network resource for which the
  1449. information is required. The lpRemoteName field of the NETRESOURCE
  1450. specifies the remote name of the network resource whose information
  1451. is required. If the calling program knows the values for the
  1452. lpProvider and dwType fields, then it should fill them in, otherwise,
  1453. it should set them to NULL. All other fields in the NETRESOURCE are
  1454. ignored and are not initialized.
  1455. lpBuffer - A pointer to the buffer to receive the result, which is
  1456. returned as a single NETRESOURCE entry representing the parent
  1457. resource. The lpRemoteName, lpProvider, dwType, and dwUsage fields
  1458. are returned, all other fields being set to NULL. The remote name
  1459. returned should be in the same syntax as that returned from an
  1460. enumeration, so that the caller can do a case sensitive string
  1461. compare to determine whether an enumerated resource is this resource.
  1462. If the provider owns a parent of the network resource, (in other
  1463. words is known to be the correct network to respond to this request),
  1464. then lpProvider should be filled in with a non-null entry. If it is
  1465. known that a network owns a parent of the resource, but that the
  1466. resource itself is not valid, then lpProvider is returned as a
  1467. non-null value together with a return status of WN_BAD_VALUE. dwScope
  1468. is returned as RESOURCE_CONTEXT if the network resource is part of
  1469. the user's network context, otherwise it is returned as zero.
  1470. cbBuffer - This specifies the size in bytes of the buffer passed to the
  1471. function call. If the result is WN_MORE_DATA, this will contain the
  1472. buffer size required (in bytes) to hold the NETRESOURCE information.
  1473. lplpSystem - Returned pointer to a string in the buffer pointed to by
  1474. lpBuffer that specifies the part of the resource that is accessed
  1475. through resource type specific system APIs rather than WNet APIs.
  1476. For example, if the input remote resource name was
  1477. "\\server\share\dir", then lpRemoteName is returned pointing to
  1478. "\\server\share" and lplpSystem points to "\dir", both strings
  1479. being stored in the buffer pointed to by lpBuffer.
  1480. Return Value:
  1481. WN_SUCCESS - If the call is successful.
  1482. WN_MORE_DATA - If input buffer is too small.
  1483. WN_BAD_VALUE - Invalid dwScope or dwUsage or dwType, or bad combination
  1484. of parameters is specified (e.g. lpRemoteName does not correspond
  1485. to dwType).
  1486. WN_BAD_NETNAME - The resource is not recognized by this provider.
  1487. --*/
  1488. {
  1489. DWORD status;
  1490. LPWSTR pszRemoteName = NULL;
  1491. DWORD BytesNeeded = 0;
  1492. DWORD SystemOffset = 0;
  1493. *lplpSystem = NULL;
  1494. status = NwpMapNameToUNC( lpNetResource->lpRemoteName, &pszRemoteName );
  1495. if (status != NO_ERROR)
  1496. {
  1497. SetLastError(status);
  1498. return status;
  1499. }
  1500. #if DBG
  1501. IF_DEBUG(CONNECT)
  1502. {
  1503. KdPrint(("\nNWPROVAU: NPGetResourceInformation %ws\n", pszRemoteName));
  1504. }
  1505. #endif
  1506. RpcTryExcept
  1507. {
  1508. if (lpNetResource->dwType != RESOURCETYPE_ANY &&
  1509. lpNetResource->dwType != RESOURCETYPE_DISK &&
  1510. lpNetResource->dwType != RESOURCETYPE_PRINT)
  1511. {
  1512. status = WN_BAD_VALUE;
  1513. }
  1514. else
  1515. {
  1516. status = NwrGetResourceInformation(
  1517. NULL,
  1518. pszRemoteName,
  1519. lpNetResource->dwType,
  1520. (LPBYTE) lpBuffer,
  1521. *cbBuffer,
  1522. &BytesNeeded,
  1523. &SystemOffset
  1524. );
  1525. if (status == WN_MORE_DATA)
  1526. {
  1527. //
  1528. // Output buffer too small.
  1529. //
  1530. *cbBuffer = BytesNeeded;
  1531. }
  1532. }
  1533. }
  1534. RpcExcept(1)
  1535. {
  1536. status = NwpMapRpcError(RpcExceptionCode());
  1537. }
  1538. RpcEndExcept
  1539. if ( pszRemoteName )
  1540. LocalFree( (HLOCAL) pszRemoteName );
  1541. if (status != NO_ERROR)
  1542. {
  1543. SetLastError(status);
  1544. }
  1545. else
  1546. {
  1547. //
  1548. // Convert offsets of strings to pointers
  1549. //
  1550. DWORD i;
  1551. LPNETRESOURCEW NetR = lpBuffer;
  1552. if (NetR->lpLocalName != NULL)
  1553. {
  1554. NetR->lpLocalName = (LPWSTR) ((DWORD_PTR) lpBuffer +
  1555. (DWORD_PTR) NetR->lpLocalName);
  1556. }
  1557. NetR->lpRemoteName = (LPWSTR) ((DWORD_PTR) lpBuffer +
  1558. (DWORD_PTR) NetR->lpRemoteName);
  1559. if (NetR->lpComment != NULL)
  1560. {
  1561. NetR->lpComment = (LPWSTR) ((DWORD_PTR) lpBuffer +
  1562. (DWORD_PTR) NetR->lpComment);
  1563. }
  1564. if (NetR->lpProvider != NULL)
  1565. {
  1566. NetR->lpProvider = (LPWSTR) ((DWORD_PTR) lpBuffer +
  1567. (DWORD_PTR) NetR->lpProvider);
  1568. }
  1569. if (SystemOffset != 0)
  1570. {
  1571. *lplpSystem = (LPWSTR) ((DWORD_PTR) lpBuffer + SystemOffset);
  1572. }
  1573. }
  1574. return status;
  1575. }
  1576. DWORD
  1577. APIENTRY
  1578. NPGetResourceParent(
  1579. LPNETRESOURCEW lpNetResource,
  1580. LPVOID lpBuffer,
  1581. LPDWORD cbBuffer
  1582. )
  1583. /*++
  1584. Routine Description:
  1585. This function returns an object which details information
  1586. about the parent of a specified network resource.
  1587. Arguments:
  1588. lpNetResource - This specifies the network resource for which the
  1589. parent name is required. The NETRESOURCE could have been obtained via
  1590. previous NPEnumResource, or constructed by the caller. The lpRemoteName
  1591. field of the NETRESOURCE specifies the remote name of the network
  1592. resouce whose parent name is required. If the calling program knows
  1593. the values for the lpProvider and dwType fields, then it can fill
  1594. them in, otherwise, they are set to NULL. If the lpProvider field is
  1595. not NULL, then the network provider DLL can assume that the resource
  1596. is owned by its network, but if it is NULL, then it must assume
  1597. that the resource could be for some other network and do whatever
  1598. checking is neccessary to ensure that the result returned is accurate.
  1599. For example, if being asked for the parent of a server, and the server
  1600. is not part of a workgroup, the the network provider DLL should check
  1601. to ensure that the server is part of its network and, if so, return
  1602. its provider name. All other fields in the NETRESOURCE are ignored and
  1603. are not initialized.
  1604. lpBuffer - A pointer to the buffer to receive the result, which is
  1605. returned as a single NETRESOURCE entry representing the parent
  1606. resource. The lpRemoteName, lpProvider, dwType, and dwUsage fields
  1607. are returned, all other fields being set to NULL. lpProvider should
  1608. be set to NULL if the provider has only done a syntactic check (i.e.
  1609. does not know that the resource is specific to its network). If the
  1610. provider owns a parent of the network resource, (in other words is
  1611. known to be the correct network to respond to this request), then
  1612. lpProvider should be filled in with a non-null entry, even if the
  1613. return is WN_BAD_VALUE. The remote name returned should be in the
  1614. same syntax as that returned from an enumeration, so that the caller
  1615. can do a case sensitive string compare to determine whether an
  1616. enumerated resource is this resource. If a resource has no browse
  1617. parent on the network, the lpRemoteName is returned as NULL. The
  1618. RESOURCEUSAGE_CONNECTABLE value in the dwUsage field does not
  1619. indicate that the resource can currently be connected to, but that
  1620. the resource is connectable when it is available on the network.
  1621. cbBuffer - This specifies the size in bytes of the buffer passed to the
  1622. function call. If the result is WN_MORE_DATA, this will contain the
  1623. buffer size required (in bytes) to hold the NETRESOURCE information.
  1624. Return Value:
  1625. WN_SUCCESS - If the call is successful.
  1626. WN_MORE_DATA - If input buffer is too small.
  1627. WN_BAD_VALUE - Invalid dwScope or dwUsage or dwType, or bad combination
  1628. of parameters is specified (e.g. lpRemoteName does not correspond
  1629. to dwType).
  1630. --*/
  1631. {
  1632. DWORD status;
  1633. LPWSTR pszRemoteName = NULL;
  1634. DWORD BytesNeeded = 0;
  1635. status = NwpMapNameToUNC( lpNetResource->lpRemoteName, &pszRemoteName );
  1636. if (status != NO_ERROR)
  1637. {
  1638. SetLastError(status);
  1639. return status;
  1640. }
  1641. #if DBG
  1642. IF_DEBUG(CONNECT)
  1643. {
  1644. KdPrint(("\nNWPROVAU: NPGetResourceParent %ws\n", pszRemoteName));
  1645. }
  1646. #endif
  1647. RpcTryExcept
  1648. {
  1649. if (lpNetResource->dwType != RESOURCETYPE_ANY &&
  1650. lpNetResource->dwType != RESOURCETYPE_DISK &&
  1651. lpNetResource->dwType != RESOURCETYPE_PRINT)
  1652. {
  1653. status = WN_BAD_VALUE;
  1654. }
  1655. else
  1656. {
  1657. status = NwrGetResourceParent(
  1658. NULL,
  1659. pszRemoteName,
  1660. lpNetResource->dwType,
  1661. (LPBYTE) lpBuffer,
  1662. *cbBuffer,
  1663. &BytesNeeded
  1664. );
  1665. if (status == WN_MORE_DATA)
  1666. {
  1667. //
  1668. // Output buffer too small.
  1669. //
  1670. *cbBuffer = BytesNeeded;
  1671. }
  1672. }
  1673. }
  1674. RpcExcept(1)
  1675. {
  1676. status = NwpMapRpcError(RpcExceptionCode());
  1677. }
  1678. RpcEndExcept
  1679. if ( pszRemoteName )
  1680. LocalFree( (HLOCAL) pszRemoteName );
  1681. if (status != NO_ERROR)
  1682. {
  1683. SetLastError(status);
  1684. }
  1685. else
  1686. {
  1687. //
  1688. // Convert offsets of strings to pointers
  1689. //
  1690. DWORD i;
  1691. LPNETRESOURCEW NetR = lpBuffer;
  1692. if (NetR->lpLocalName != NULL)
  1693. {
  1694. NetR->lpLocalName = (LPWSTR) ((DWORD_PTR) lpBuffer +
  1695. (DWORD_PTR) NetR->lpLocalName);
  1696. }
  1697. NetR->lpRemoteName = (LPWSTR) ((DWORD_PTR) lpBuffer +
  1698. (DWORD_PTR) NetR->lpRemoteName);
  1699. if (NetR->lpComment != NULL)
  1700. {
  1701. NetR->lpComment = (LPWSTR) ((DWORD_PTR) lpBuffer +
  1702. (DWORD_PTR) NetR->lpComment);
  1703. }
  1704. if (NetR->lpProvider != NULL)
  1705. {
  1706. NetR->lpProvider = (LPWSTR) ((DWORD_PTR) lpBuffer +
  1707. (DWORD_PTR) NetR->lpProvider);
  1708. }
  1709. }
  1710. return status;
  1711. }
  1712. DWORD
  1713. APIENTRY
  1714. NwEnumConnections(
  1715. HANDLE hEnum,
  1716. LPDWORD lpcCount,
  1717. LPVOID lpBuffer,
  1718. LPDWORD lpBufferSize,
  1719. BOOL fImplicitConnections
  1720. )
  1721. /*++
  1722. Routine Description:
  1723. This function returns a lists of connections.
  1724. Arguments:
  1725. hEnum - Supplies the resumable enumeration context handle.
  1726. NOTE: If this value is 0xFFFFFFFF, it is not a context
  1727. handle and this routine is required to return
  1728. WN_NO_MORE_ENTRIES. This hack is to handle the
  1729. case where the user cancelled out of the network
  1730. credential dialog on NwrOpenEnumDirectories and we
  1731. cannot return an error there or we generate an error
  1732. popup.
  1733. lpcCount - On input, supplies the number of entries to get.
  1734. On output, if NO_ERROR is returned, receives the number
  1735. of entries NETRESOURCE returned in lpBuffer.
  1736. lpBuffer - Receives an array of NETRESOURCE entries, each
  1737. entry describes an object within the container.
  1738. lpBufferSize - On input, supplies the size of lpBuffer in
  1739. bytes. On output, if WN_MORE_DATA is returned, receives
  1740. the number of bytes needed in the buffer to get the
  1741. next entry.
  1742. fImplicitConnections - TRUE is we also want all implicit connections,
  1743. FALSE otherwise.
  1744. Return Value:
  1745. NO_ERROR - Successfully returned at least one entry.
  1746. WN_NO_MORE_ENTRIES - Reached the end of enumeration and nothing
  1747. is returned.
  1748. WN_MORE_DATA - lpBuffer is too small to even get one entry.
  1749. WN_BAD_HANDLE - The enumeration handle is invalid.
  1750. Other network errors.
  1751. --*/
  1752. {
  1753. DWORD status = NO_ERROR;
  1754. DWORD BytesNeeded = 0;
  1755. DWORD EntriesRead = 0;
  1756. #if DBG
  1757. IF_DEBUG(ENUM) {
  1758. KdPrint(("\nNWPROVAU: NPEnumResource\n"));
  1759. }
  1760. #endif
  1761. RpcTryExcept {
  1762. if (hEnum == (HANDLE) 0xFFFFFFFF) {
  1763. status = WN_NO_MORE_ENTRIES;
  1764. goto EndOfTry;
  1765. }
  1766. status = NwrEnumConnections(
  1767. (NWWKSTA_CONTEXT_HANDLE) hEnum,
  1768. *lpcCount,
  1769. (LPBYTE) lpBuffer,
  1770. *lpBufferSize,
  1771. &BytesNeeded,
  1772. &EntriesRead,
  1773. fImplicitConnections
  1774. );
  1775. if (status == WN_MORE_DATA) {
  1776. //
  1777. // Output buffer too small to fit a single entry.
  1778. //
  1779. *lpBufferSize = BytesNeeded;
  1780. }
  1781. else if (status == NO_ERROR) {
  1782. *lpcCount = EntriesRead;
  1783. }
  1784. EndOfTry: ;
  1785. }
  1786. RpcExcept(1) {
  1787. status = NwpMapRpcError(RpcExceptionCode());
  1788. }
  1789. RpcEndExcept
  1790. if (status != NO_ERROR && status != WN_NO_MORE_ENTRIES) {
  1791. SetLastError(status);
  1792. }
  1793. //
  1794. // Convert offsets of strings to pointers
  1795. //
  1796. if (EntriesRead > 0) {
  1797. DWORD i;
  1798. LPNETRESOURCEW NetR;
  1799. NetR = lpBuffer;
  1800. for (i = 0; i < EntriesRead; i++, NetR++) {
  1801. if (NetR->lpLocalName != NULL) {
  1802. NetR->lpLocalName = (LPWSTR) ((DWORD_PTR) lpBuffer +
  1803. (DWORD_PTR) NetR->lpLocalName);
  1804. }
  1805. NetR->lpRemoteName = (LPWSTR) ((DWORD_PTR) lpBuffer +
  1806. (DWORD_PTR) NetR->lpRemoteName);
  1807. if (NetR->lpComment != NULL) {
  1808. NetR->lpComment = (LPWSTR) ((DWORD_PTR) lpBuffer +
  1809. (DWORD_PTR) NetR->lpComment);
  1810. }
  1811. if (NetR->lpProvider != NULL) {
  1812. NetR->lpProvider = (LPWSTR) ((DWORD_PTR) lpBuffer +
  1813. (DWORD_PTR) NetR->lpProvider);
  1814. }
  1815. }
  1816. }
  1817. return status;
  1818. }
  1819. DWORD
  1820. APIENTRY
  1821. NPCloseEnum(
  1822. HANDLE hEnum
  1823. )
  1824. /*++
  1825. Routine Description:
  1826. This function closes the enumeration context handle.
  1827. Arguments:
  1828. hEnum - Supplies the enumeration context handle.
  1829. NOTE: If this value is 0xFFFFFFFF, it is not a context
  1830. handle. Just return success.
  1831. Return Value:
  1832. NO_ERROR - Successfully returned at least one entry.
  1833. WN_BAD_HANDLE - The enumeration handle is invalid.
  1834. --*/
  1835. {
  1836. DWORD status = NO_ERROR;
  1837. #if DBG
  1838. IF_DEBUG(ENUM) {
  1839. KdPrint(("\nNWPROVAU: NPCloseEnum\n"));
  1840. }
  1841. #endif
  1842. RpcTryExcept
  1843. {
  1844. if (hEnum == (HANDLE) 0xFFFFFFFF) {
  1845. status = NO_ERROR;
  1846. }
  1847. else {
  1848. status = NwrCloseEnum(
  1849. (LPNWWKSTA_CONTEXT_HANDLE) &hEnum
  1850. );
  1851. }
  1852. }
  1853. RpcExcept(1) {
  1854. status = NwpMapRpcError(RpcExceptionCode());
  1855. }
  1856. RpcEndExcept
  1857. if (status != NO_ERROR) {
  1858. SetLastError(status);
  1859. }
  1860. return status;
  1861. }
  1862. DWORD
  1863. APIENTRY
  1864. NPFormatNetworkName(
  1865. LPWSTR lpRemoteName,
  1866. LPWSTR lpFormattedName,
  1867. LPDWORD lpnLength,
  1868. DWORD dwFlags,
  1869. DWORD dwAveCharPerLine
  1870. )
  1871. /*++
  1872. Routine Description:
  1873. This function takes a fully-qualified UNC name and formats it
  1874. into a shorter form for display. Only the name of the object
  1875. within the container is returned for display.
  1876. We only support formatting of the remote resource name to the
  1877. abbreviated form for display during enumeration where the container
  1878. name is displayed prior to the object within it.
  1879. Arguments:
  1880. lpRemoteName - Supplies the fully-qualified UNC name.
  1881. lpFormatedName - Output buffer to receive the formatted name.
  1882. lpnLength - On input, supplies the length of the lpFormattedName
  1883. buffer in characters. On output, if WN_MORE_DATA is returned,
  1884. receives the length in number of characters required of the
  1885. output buffer to hold the formatted name.
  1886. dwFlags - Supplies a bitwise set of flags indicating the type
  1887. of formatting required on lpRemoteName.
  1888. dwAveCharPerLine - Ignored.
  1889. Return Value:
  1890. NO_ERROR - Successfully returned at least one entry.
  1891. WN_MORE_DATA - lpFormattedName buffer is too small.
  1892. WN_BAD_VALUE - lpRemoteName is NULL.
  1893. ERROR_NOT_SUPPORTED - dwFlags that does not contain the
  1894. WNFMT_INENUM bit.
  1895. --*/
  1896. {
  1897. DWORD status = NO_ERROR;
  1898. LPWSTR NextBackSlash;
  1899. LPWSTR Source;
  1900. DWORD SourceLen;
  1901. #if DBG
  1902. IF_DEBUG(OTHER)
  1903. KdPrint(("\nNWPROVAU: NPFormatNetworkName\n"));
  1904. #endif
  1905. if (lpRemoteName == NULL)
  1906. {
  1907. status = WN_BAD_VALUE;
  1908. goto CleanExit;
  1909. }
  1910. if (dwFlags & WNFMT_INENUM)
  1911. {
  1912. BYTE i;
  1913. WORD length = (WORD) wcslen( lpRemoteName );
  1914. WORD slashCount = 0;
  1915. WORD dotCount = 0;
  1916. WORD Start = 0;
  1917. WORD End = length;
  1918. BOOL isNdsUnc = FALSE;
  1919. BOOL couldBeNdsUnc = FALSE;
  1920. if ( lpRemoteName[0] == L' ' )
  1921. couldBeNdsUnc = TRUE;
  1922. for ( i = 0; i < length; i++ )
  1923. {
  1924. if ( lpRemoteName[i] == L'\\' )
  1925. {
  1926. slashCount++;
  1927. if ( i + 1 < length )
  1928. {
  1929. Start = i + 1;
  1930. }
  1931. }
  1932. if ( couldBeNdsUnc &&
  1933. ( ( lpRemoteName[i] == L'.' ) ||
  1934. ( lpRemoteName[i] == L'=' ) ) )
  1935. isNdsUnc = TRUE;
  1936. if ( dotCount < 1 && isNdsUnc && lpRemoteName[i] == L'.' )
  1937. {
  1938. End = i - 1;
  1939. dotCount++;
  1940. }
  1941. }
  1942. if ( i > length )
  1943. End = length - 1;
  1944. if ( slashCount > 3 || ( isNdsUnc != TRUE && slashCount != 3 && dotCount == 0 ) )
  1945. End = i - 1;
  1946. Source = &lpRemoteName[Start];
  1947. SourceLen = End - Start + 1;
  1948. if ( SourceLen + 1 > *lpnLength )
  1949. {
  1950. *lpnLength = SourceLen + 1;
  1951. status = WN_MORE_DATA;
  1952. }
  1953. else
  1954. {
  1955. wcsncpy( lpFormattedName, Source, SourceLen );
  1956. lpFormattedName[SourceLen] = 0x00000000;
  1957. status = NO_ERROR;
  1958. }
  1959. }
  1960. else if ( dwFlags & WNFMT_MULTILINE )
  1961. {
  1962. DWORD i, j, k = 0;
  1963. DWORD nLastBackSlash = 0;
  1964. DWORD BytesNeeded = ( wcslen( lpRemoteName ) + 1 +
  1965. 2 * wcslen( lpRemoteName ) / dwAveCharPerLine
  1966. ) * sizeof( WCHAR);
  1967. if ( *lpnLength < (BytesNeeded/sizeof(WCHAR)) )
  1968. {
  1969. *lpnLength = BytesNeeded/sizeof(WCHAR);
  1970. status = WN_MORE_DATA;
  1971. goto CleanExit;
  1972. }
  1973. for ( i = 0, j = 0; lpRemoteName[i] != 0; i++, j++ )
  1974. {
  1975. if ( lpRemoteName[i] == L'\\' )
  1976. nLastBackSlash = i;
  1977. if ( k == dwAveCharPerLine )
  1978. {
  1979. if ( lpRemoteName[i] != L'\\' )
  1980. {
  1981. DWORD m, n;
  1982. for ( n = nLastBackSlash, m = ++j ; n <= i ; n++, m-- )
  1983. {
  1984. lpFormattedName[m] = lpFormattedName[m-1];
  1985. }
  1986. lpFormattedName[m] = L'\n';
  1987. k = i - nLastBackSlash - 1;
  1988. }
  1989. else
  1990. {
  1991. lpFormattedName[j++] = L'\n';
  1992. k = 0;
  1993. }
  1994. }
  1995. lpFormattedName[j] = lpRemoteName[i];
  1996. k++;
  1997. }
  1998. lpFormattedName[j] = 0;
  1999. }
  2000. else if ( dwFlags & WNFMT_ABBREVIATED )
  2001. {
  2002. //
  2003. // we dont support abbreviated form for now because we look bad
  2004. // in comdlg (fileopen) if we do.
  2005. //
  2006. DWORD nLength;
  2007. nLength = wcslen( lpRemoteName ) + 1 ;
  2008. if (nLength > *lpnLength)
  2009. {
  2010. *lpnLength = nLength;
  2011. status = WN_MORE_DATA;
  2012. goto CleanExit;
  2013. }
  2014. else
  2015. {
  2016. wcscpy( lpFormattedName, lpRemoteName );
  2017. }
  2018. #if 0
  2019. DWORD i, j, k;
  2020. DWORD BytesNeeded = dwAveCharPerLine * sizeof( WCHAR);
  2021. DWORD nLength;
  2022. if ( *lpnLength < BytesNeeded )
  2023. {
  2024. *lpnLength = BytesNeeded;
  2025. status = WN_MORE_DATA;
  2026. goto CleanExit;
  2027. }
  2028. nLength = wcslen( lpRemoteName );
  2029. if ( ( nLength + 1) <= dwAveCharPerLine )
  2030. {
  2031. wcscpy( lpFormattedName, lpRemoteName );
  2032. }
  2033. else
  2034. {
  2035. lpFormattedName[0] = lpRemoteName[0];
  2036. lpFormattedName[1] = lpRemoteName[1];
  2037. for ( i = 2; lpRemoteName[i] != L'\\'; i++ )
  2038. lpFormattedName[i] = lpRemoteName[i];
  2039. for ( j = dwAveCharPerLine-1, k = nLength; j >= (i+3); j--, k-- )
  2040. {
  2041. lpFormattedName[j] = lpRemoteName[k];
  2042. if ( lpRemoteName[k] == L'\\' )
  2043. {
  2044. j--;
  2045. break;
  2046. }
  2047. }
  2048. lpFormattedName[j] = lpFormattedName[j-1] = lpFormattedName[j-2] = L'.';
  2049. for ( k = i; k < (j-2); k++ )
  2050. lpFormattedName[k] = lpRemoteName[k];
  2051. }
  2052. #endif
  2053. }
  2054. else // some unknown flags
  2055. {
  2056. status = ERROR_NOT_SUPPORTED;
  2057. }
  2058. CleanExit:
  2059. if (status != NO_ERROR)
  2060. SetLastError(status);
  2061. return status;
  2062. }
  2063. STATIC
  2064. BOOL
  2065. NwpWorkstationStarted(
  2066. VOID
  2067. )
  2068. /*++
  2069. Routine Description:
  2070. This function queries the service controller to see if the
  2071. NetWare workstation service has started. If in doubt, it returns
  2072. FALSE.
  2073. Arguments:
  2074. None.
  2075. Return Value:
  2076. Returns TRUE if the NetWare workstation service has started,
  2077. FALSE otherwise.
  2078. --*/
  2079. {
  2080. SC_HANDLE ScManager;
  2081. SC_HANDLE Service;
  2082. SERVICE_STATUS ServiceStatus;
  2083. BOOL IsStarted = FALSE;
  2084. ScManager = OpenSCManagerW(
  2085. NULL,
  2086. NULL,
  2087. SC_MANAGER_CONNECT
  2088. );
  2089. if (ScManager == NULL) {
  2090. return FALSE;
  2091. }
  2092. Service = OpenServiceW(
  2093. ScManager,
  2094. NW_WORKSTATION_SERVICE,
  2095. SERVICE_QUERY_STATUS
  2096. );
  2097. if (Service == NULL) {
  2098. CloseServiceHandle(ScManager);
  2099. return FALSE;
  2100. }
  2101. if (! QueryServiceStatus(Service, &ServiceStatus)) {
  2102. CloseServiceHandle(ScManager);
  2103. CloseServiceHandle(Service);
  2104. return FALSE;
  2105. }
  2106. if ( (ServiceStatus.dwCurrentState == SERVICE_RUNNING) ||
  2107. (ServiceStatus.dwCurrentState == SERVICE_CONTINUE_PENDING) ||
  2108. (ServiceStatus.dwCurrentState == SERVICE_PAUSE_PENDING) ||
  2109. (ServiceStatus.dwCurrentState == SERVICE_PAUSED) ) {
  2110. IsStarted = TRUE;
  2111. }
  2112. CloseServiceHandle(ScManager);
  2113. CloseServiceHandle(Service);
  2114. return IsStarted;
  2115. }
  2116. DWORD
  2117. NwpMapNameToUNC(
  2118. IN LPWSTR pszName,
  2119. OUT LPWSTR *ppszUNC
  2120. )
  2121. /*++
  2122. Routine Description:
  2123. This routine validates the given name as a netwarepath or UNC path.
  2124. If it is a netware path, this routine will convert the
  2125. Netware path name to UNC name.
  2126. Arguments:
  2127. pszName - Supplies the netware name or UNC name
  2128. ppszUNC - Points to the converted UNC name
  2129. Return Value:
  2130. NO_ERROR or the error that occurred.
  2131. --*/
  2132. {
  2133. DWORD err = NO_ERROR;
  2134. LPWSTR pszSrc = pszName;
  2135. LPWSTR pszDest;
  2136. BOOL fSlash = FALSE;
  2137. BOOL fColon = FALSE;
  2138. DWORD nServerLen = 0;
  2139. DWORD nVolLen = 0;
  2140. BOOL fFirstToken = TRUE;
  2141. *ppszUNC = NULL;
  2142. //
  2143. // The name cannot be NULL or empty string
  2144. //
  2145. if ( pszName == NULL || *pszName == 0)
  2146. return WN_BAD_NETNAME;
  2147. #if DBG
  2148. IF_DEBUG(CONNECT)
  2149. KdPrint(("NwpMapNameToUNC: Source = %ws\n", pszName ));
  2150. #endif
  2151. //
  2152. // Get rid of the <space> if a NDS tree name ...
  2153. //
  2154. if ( pszName[0] == L' ' &&
  2155. pszName[1] == L'\\' &&
  2156. pszName[2] == L'\\' )
  2157. pszName = &pszName[1];
  2158. //
  2159. // Check if the given name is a valid UNC name
  2160. //
  2161. err = NwLibCanonRemoteName( NULL, // "\\Server" is valid UNC path
  2162. pszName,
  2163. ppszUNC,
  2164. NULL );
  2165. //
  2166. // The given name is a valid UNC name, so return success!
  2167. //
  2168. if ( err == NO_ERROR )
  2169. return err;
  2170. //
  2171. // Allocate the buffer to store the mapped UNC name
  2172. // We allocate 3 extra characters, two for the backslashes in front
  2173. // and one for the ease of parsing below.
  2174. //
  2175. if ((*ppszUNC = (LPVOID) LocalAlloc(
  2176. LMEM_ZEROINIT,
  2177. (wcslen( pszName) + 4) * sizeof( WCHAR)
  2178. )) == NULL )
  2179. {
  2180. return ERROR_NOT_ENOUGH_MEMORY;
  2181. }
  2182. wcscpy( *ppszUNC, L"\\\\" );
  2183. pszDest = *ppszUNC + 2; // Skip past two backslashes
  2184. //
  2185. // Parse the given string and put the converted string into *ppszUNC
  2186. // In the converted string, we will substitute 0 for all slashes
  2187. // for the time being.
  2188. //
  2189. for ( ; *pszSrc != 0; pszSrc++ )
  2190. {
  2191. if ( ( *pszSrc == L'/' )
  2192. || ( *pszSrc == L'\\' )
  2193. )
  2194. {
  2195. //
  2196. // Two consecutive backslashes are bad
  2197. //
  2198. if ( (*(pszSrc+1) == L'/') || (*(pszSrc+1) == L'\\'))
  2199. {
  2200. LocalFree( *ppszUNC );
  2201. *ppszUNC = NULL;
  2202. return WN_BAD_NETNAME;
  2203. }
  2204. if ( !fSlash )
  2205. fSlash = TRUE;
  2206. *pszDest++ = 0;
  2207. }
  2208. else if ( (*pszSrc == L':') && fSlash && !fColon )
  2209. {
  2210. fColon = TRUE;
  2211. if ( *(pszSrc+1) != 0 )
  2212. *pszDest++ = 0;
  2213. }
  2214. else
  2215. {
  2216. *pszDest++ = *pszSrc;
  2217. if (( fSlash ) && ( !fColon))
  2218. nVolLen++;
  2219. else if ( !fSlash )
  2220. nServerLen++;
  2221. }
  2222. }
  2223. //
  2224. // Note: *ppszUNC is already terminated with two '\0' because we initialized
  2225. // the whole buffer to zero.
  2226. //
  2227. if ( ( nServerLen == 0 )
  2228. || ( fSlash && nVolLen == 0 )
  2229. || ( fSlash && nVolLen != 0 && !fColon )
  2230. )
  2231. {
  2232. LocalFree( *ppszUNC );
  2233. *ppszUNC = NULL;
  2234. return WN_BAD_NETNAME;
  2235. }
  2236. //
  2237. // At this point, we know the name is a valid Netware syntax
  2238. // i.e. SERVER[/VOL:/dir]
  2239. // We now need to validate that all the characters used in the
  2240. // servername, volume, directory are valid characters
  2241. //
  2242. pszDest = *ppszUNC + 2; // Skip past the first two backslashes
  2243. while ( *pszDest != 0 )
  2244. {
  2245. DWORD nLen = wcslen( pszDest );
  2246. if ( ( fFirstToken && !IS_VALID_SERVER_TOKEN( pszDest, nLen ))
  2247. || ( !fFirstToken && !IS_VALID_TOKEN( pszDest, nLen ))
  2248. )
  2249. {
  2250. LocalFree( *ppszUNC );
  2251. *ppszUNC = NULL;
  2252. return WN_BAD_NETNAME;
  2253. }
  2254. fFirstToken = FALSE;
  2255. pszDest += nLen + 1;
  2256. }
  2257. //
  2258. // The netware name is valid! Convert 0 back to backslash in
  2259. // converted string.
  2260. //
  2261. pszDest = *ppszUNC + 2; // Skip past the first two backslashes
  2262. while ( *pszDest != 0 )
  2263. {
  2264. if ( (*(pszDest+1) == 0 ) && (*(pszDest+2) != 0 ) )
  2265. {
  2266. *(pszDest+1) = L'\\';
  2267. }
  2268. pszDest++;
  2269. }
  2270. #if DBG
  2271. IF_DEBUG(CONNECT)
  2272. KdPrint(("NwpMapNameToUNC: Destination = %ws\n", *ppszUNC ));
  2273. #endif
  2274. return NO_ERROR;
  2275. }
  2276. STATIC
  2277. VOID
  2278. NwpGetUncInfo(
  2279. IN LPWSTR lpstrUnc,
  2280. OUT WORD * slashCount,
  2281. OUT BOOL * isNdsUnc
  2282. )
  2283. {
  2284. BYTE i;
  2285. WORD length = (WORD) wcslen( lpstrUnc );
  2286. *isNdsUnc = FALSE;
  2287. *slashCount = 0;
  2288. for ( i = 0; i < length; i++ )
  2289. {
  2290. if ( ( lpstrUnc[i] == L'.' ) && ( *slashCount == 3 ) )
  2291. {
  2292. *isNdsUnc = TRUE;
  2293. }
  2294. if ( lpstrUnc[i] == L'\\' )
  2295. {
  2296. *slashCount += 1;
  2297. }
  2298. }
  2299. }
  2300. STATIC
  2301. LPWSTR
  2302. NwpGetUncObjectName(
  2303. IN LPWSTR ContainerName
  2304. )
  2305. {
  2306. WORD length = 2;
  2307. WORD totalLength = (WORD) wcslen( ContainerName );
  2308. if ( totalLength < 2 )
  2309. return 0;
  2310. while ( length < totalLength )
  2311. {
  2312. if ( ContainerName[length] == L'.' )
  2313. ContainerName[length] = L'\0';
  2314. length++;
  2315. }
  2316. length = 2;
  2317. while ( length < totalLength && ContainerName[length] != L'\\' )
  2318. {
  2319. length++;
  2320. }
  2321. if ( ( ContainerName[length + 1] == L'C' ||
  2322. ContainerName[length + 1] == L'c' ) &&
  2323. ( ContainerName[length + 2] == L'N' ||
  2324. ContainerName[length + 2] == L'n' ) &&
  2325. ContainerName[length + 3] == L'=' )
  2326. {
  2327. ContainerName[length + 2] = L'\\';
  2328. ContainerName[length + 3] = L'\\';
  2329. return (ContainerName + length + 2);
  2330. }
  2331. ContainerName[length - 1] = L'\\';
  2332. return (ContainerName + length - 1);
  2333. }
  2334. STATIC
  2335. WORD
  2336. NwpGetSlashCount(
  2337. IN LPWSTR lpstrUnc
  2338. )
  2339. {
  2340. WORD count = 0;
  2341. BYTE i;
  2342. WORD length = (WORD) wcslen( lpstrUnc );
  2343. for ( i = 0; i < length; i++ )
  2344. {
  2345. if ( lpstrUnc[i] == L'\\' )
  2346. {
  2347. count++;
  2348. }
  2349. }
  2350. return count;
  2351. }
  2352. DWORD
  2353. NwpMapRpcError(
  2354. IN DWORD RpcError
  2355. )
  2356. /*++
  2357. Routine Description:
  2358. This routine maps the RPC error into a more meaningful windows
  2359. error for the caller.
  2360. Arguments:
  2361. RpcError - Supplies the exception error raised by RPC
  2362. Return Value:
  2363. Returns the mapped error.
  2364. --*/
  2365. {
  2366. switch (RpcError) {
  2367. case RPC_S_UNKNOWN_IF:
  2368. case RPC_S_SERVER_UNAVAILABLE:
  2369. return WN_NO_NETWORK;
  2370. case RPC_S_INVALID_BINDING:
  2371. case RPC_X_SS_IN_NULL_CONTEXT:
  2372. case RPC_X_SS_CONTEXT_DAMAGED:
  2373. case RPC_X_SS_HANDLES_MISMATCH:
  2374. case ERROR_INVALID_HANDLE:
  2375. return ERROR_INVALID_HANDLE;
  2376. case RPC_X_NULL_REF_POINTER:
  2377. return ERROR_INVALID_PARAMETER;
  2378. case EXCEPTION_ACCESS_VIOLATION:
  2379. return ERROR_INVALID_ADDRESS;
  2380. default:
  2381. return RpcError;
  2382. }
  2383. }
  2384. DWORD
  2385. NwRegisterGatewayShare(
  2386. IN LPWSTR ShareName,
  2387. IN LPWSTR DriveName
  2388. )
  2389. /*++
  2390. Routine Description:
  2391. This routine remembers that a gateway share has been created so
  2392. that it can be cleanup up when NWCS is uninstalled.
  2393. Arguments:
  2394. ShareName - name of share
  2395. DriveName - name of drive that is shared
  2396. Return Status:
  2397. Win32 error of any failure.
  2398. --*/
  2399. {
  2400. return ( NwpRegisterGatewayShare(ShareName, DriveName) ) ;
  2401. }
  2402. DWORD
  2403. NwCleanupGatewayShares(
  2404. VOID
  2405. )
  2406. /*++
  2407. Routine Description:
  2408. This routine cleans up all persistent share info and also tidies
  2409. up the registry for NWCS. Later is not needed in uninstall, but is
  2410. there so we have a single routine that cvompletely disables the
  2411. gateway.
  2412. Arguments:
  2413. None.
  2414. Return Status:
  2415. Win32 error for failed APIs.
  2416. --*/
  2417. {
  2418. return ( NwpCleanupGatewayShares() ) ;
  2419. }
  2420. DWORD
  2421. NwClearGatewayShare(
  2422. IN LPWSTR ShareName
  2423. )
  2424. /*++
  2425. Routine Description:
  2426. This routine deletes a specific share from the remembered gateway
  2427. shares in the registry.
  2428. Arguments:
  2429. ShareName - share value to delete
  2430. Return Status:
  2431. Win32 status code.
  2432. --*/
  2433. {
  2434. return ( NwpClearGatewayShare( ShareName ) ) ;
  2435. }