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.

2994 lines
88 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. LPWSTR lpNewBuffer;
  786. if (!(lpNewBuffer = (LPWSTR) LocalReAlloc(
  787. (HLOCAL) lpRemoteBuffer,
  788. dwCharsRequired * sizeof(WCHAR),
  789. LMEM_MOVEABLE)))
  790. {
  791. status = GetLastError() ;
  792. LocalFree(lpRemoteBuffer);
  793. lpRemoteBuffer = NULL;
  794. goto ErrorExit ;
  795. }
  796. lpRemoteBuffer = lpNewBuffer;
  797. status = NPGetConnection(
  798. szDrive,
  799. lpRemoteBuffer,
  800. &dwCharsRequired) ;
  801. }
  802. if (status != WN_SUCCESS)
  803. {
  804. goto ErrorExit ;
  805. }
  806. //
  807. // at minimum we will need this size of the UNC name
  808. // the -2 is because we loose the drive letter & colon.
  809. //
  810. dwBytesNeeded = (wcslen(lpRemoteBuffer) +
  811. dwLocalLength - 2 + 1) * sizeof(WCHAR) ;
  812. switch (dwInfoLevel)
  813. {
  814. case UNIVERSAL_NAME_INFO_LEVEL:
  815. {
  816. LPUNIVERSAL_NAME_INFO lpUniversalNameInfo ;
  817. //
  818. // calculate how many bytes we really need
  819. //
  820. dwBytesNeeded += sizeof(UNIVERSAL_NAME_INFO) ;
  821. if (*lpBufferSize < dwBytesNeeded)
  822. {
  823. *lpBufferSize = dwBytesNeeded ;
  824. status = WN_MORE_DATA ;
  825. break ;
  826. }
  827. //
  828. // now we are all set. just stick the data in the buffer
  829. //
  830. lpUniversalNameInfo = (LPUNIVERSAL_NAME_INFO) lpBuffer ;
  831. lpUniversalNameInfo->lpUniversalName = (LPWSTR)
  832. (((LPBYTE)lpBuffer) + sizeof(UNIVERSAL_NAME_INFO)) ;
  833. wcscpy(lpUniversalNameInfo->lpUniversalName,
  834. lpRemoteBuffer) ;
  835. wcscat(lpUniversalNameInfo->lpUniversalName,
  836. lpLocalPath+2) ;
  837. break ;
  838. }
  839. case REMOTE_NAME_INFO_LEVEL :
  840. {
  841. LPREMOTE_NAME_INFO lpRemoteNameInfo ;
  842. //
  843. // calculate how many bytes we really need
  844. //
  845. dwBytesNeeded *= 2 ; // essentially twice the info + terminator
  846. dwBytesNeeded += (sizeof(REMOTE_NAME_INFO) + sizeof(WCHAR)) ;
  847. if (*lpBufferSize < dwBytesNeeded)
  848. {
  849. *lpBufferSize = dwBytesNeeded ;
  850. status = WN_MORE_DATA ;
  851. break ;
  852. }
  853. //
  854. // now we are all set. just stick the data in the buffer
  855. //
  856. lpRemoteNameInfo = (LPREMOTE_NAME_INFO) lpBuffer ;
  857. lpRemoteNameInfo->lpUniversalName = (LPWSTR)
  858. (((LPBYTE)lpBuffer) + sizeof(REMOTE_NAME_INFO)) ;
  859. wcscpy(lpRemoteNameInfo->lpUniversalName,
  860. lpRemoteBuffer) ;
  861. wcscat(lpRemoteNameInfo->lpUniversalName,
  862. lpLocalPath+2) ;
  863. lpRemoteNameInfo->lpConnectionName =
  864. lpRemoteNameInfo->lpUniversalName +
  865. wcslen(lpRemoteNameInfo->lpUniversalName) + 1 ;
  866. wcscpy(lpRemoteNameInfo->lpConnectionName,
  867. lpRemoteBuffer) ;
  868. lpRemoteNameInfo->lpRemainingPath =
  869. lpRemoteNameInfo->lpConnectionName +
  870. wcslen(lpRemoteNameInfo->lpConnectionName) + 1 ;
  871. wcscpy(lpRemoteNameInfo->lpRemainingPath,
  872. lpLocalPath+2) ;
  873. break ;
  874. }
  875. default:
  876. //
  877. // yikes!
  878. //
  879. status = WN_BAD_VALUE ;
  880. ASSERT(FALSE);
  881. }
  882. ErrorExit:
  883. if (lpRemoteBuffer)
  884. {
  885. (void) LocalFree((HLOCAL)lpRemoteBuffer) ;
  886. }
  887. return status;
  888. }
  889. DWORD
  890. APIENTRY
  891. NPOpenEnum(
  892. DWORD dwScope,
  893. DWORD dwType,
  894. DWORD dwUsage,
  895. LPNETRESOURCEW lpNetResource,
  896. LPHANDLE lphEnum
  897. )
  898. /*++
  899. Routine Description:
  900. This function initiates an enumeration of either connections, or
  901. browsing of network resource.
  902. Arguments:
  903. dwScope - Supplies the category of enumeration to do--either
  904. connection or network browsing.
  905. dwType - Supplies the type of resource to get--either disk,
  906. print, or it does not matter.
  907. dwUsage - Supplies the object type to get--either container,
  908. or connectable usage.
  909. lpNetResource - Supplies, in the lpRemoteName field, the container
  910. name to enumerate under.
  911. lphEnum - Receives the resumable context handle to be used on all
  912. subsequent calls to get the list of objects under the container.
  913. Return Value:
  914. NO_ERROR - Successful.
  915. WN_BAD_VALUE - Either the dwScope, dwType, or the dwUsage specified
  916. is not acceptable.
  917. WN_BAD_NETNAME - Invalid remote resource name.
  918. WN_NOT_CONTAINER - Remote resource name is not a container.
  919. Other network errors.
  920. --*/
  921. {
  922. DWORD status = NO_ERROR;
  923. #if DBG
  924. IF_DEBUG(ENUM)
  925. {
  926. KdPrint(("\nNWPROVAU: NPOpenEnum\n"));
  927. }
  928. #endif
  929. RpcTryExcept
  930. {
  931. if ( ( dwType & RESOURCETYPE_DISK ) ||
  932. ( dwType & RESOURCETYPE_PRINT ) ||
  933. ( dwType == RESOURCETYPE_ANY ) )
  934. {
  935. switch ( dwScope )
  936. {
  937. case RESOURCE_CONNECTED:
  938. status = NwrOpenEnumConnections( NULL,
  939. dwType,
  940. (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
  941. break;
  942. case RESOURCE_CONTEXT:
  943. status = NwrOpenEnumContextInfo( NULL,
  944. dwType,
  945. (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
  946. break;
  947. case RESOURCE_GLOBALNET:
  948. if ( lpNetResource == NULL )
  949. {
  950. //
  951. // Enumerating servers and NDS trees
  952. //
  953. if ( dwUsage & RESOURCEUSAGE_CONTAINER || dwUsage == 0 )
  954. {
  955. status = NwrOpenEnumServersAndNdsTrees( NULL,
  956. (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
  957. }
  958. else
  959. {
  960. //
  961. // There is no such thing as a connectable server
  962. // object.
  963. //
  964. status = WN_BAD_VALUE;
  965. }
  966. }
  967. else
  968. {
  969. BOOL IsEnumVolumes = TRUE;
  970. LPWSTR pszRemoteName = NULL;
  971. WORD slashCount;
  972. BOOL isNdsUnc;
  973. NwpGetUncInfo( lpNetResource->lpRemoteName,
  974. &slashCount,
  975. &isNdsUnc );
  976. //
  977. // Either enumerating volumes, directories, or NDS subtrees
  978. //
  979. if ( dwUsage & RESOURCEUSAGE_CONNECTABLE ||
  980. dwUsage & RESOURCEUSAGE_CONTAINER ||
  981. dwUsage == 0 )
  982. {
  983. LPWSTR tempStrPtr = lpNetResource->lpRemoteName;
  984. DWORD dwClassType = 0;
  985. //
  986. // Get rid of the <space> if a NDS tree name ...
  987. //
  988. if ( tempStrPtr[0] == L' ' &&
  989. tempStrPtr[1] == L'\\' &&
  990. tempStrPtr[2] == L'\\' )
  991. tempStrPtr = &tempStrPtr[1];
  992. if ( lpNetResource->dwDisplayType == RESOURCEDISPLAYTYPE_TREE )
  993. {
  994. if ( ( dwType == RESOURCETYPE_ANY ) ||
  995. ( ( dwType & RESOURCETYPE_DISK ) &&
  996. ( dwType & RESOURCETYPE_PRINT ) ) )
  997. {
  998. status = NwrOpenEnumNdsSubTrees_Any( NULL,
  999. tempStrPtr,
  1000. NULL,
  1001. (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
  1002. }
  1003. else if ( dwType & RESOURCETYPE_DISK )
  1004. {
  1005. status = NwrOpenEnumNdsSubTrees_Disk( NULL,
  1006. tempStrPtr,
  1007. NULL,
  1008. (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
  1009. }
  1010. else if ( dwType & RESOURCETYPE_PRINT )
  1011. {
  1012. status = NwrOpenEnumNdsSubTrees_Print( NULL,
  1013. tempStrPtr,
  1014. NULL,
  1015. (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
  1016. }
  1017. else
  1018. {
  1019. KdPrint(("NWOpenEnum: Unhandled dwType %lu\n", dwType));
  1020. }
  1021. }
  1022. else if (
  1023. ( slashCount < 4 ) &&
  1024. ( ( dwType == RESOURCETYPE_ANY ) ||
  1025. ( ( dwType & RESOURCETYPE_DISK ) &&
  1026. ( dwType & RESOURCETYPE_PRINT ) ) ) &&
  1027. ( ( status = NwrOpenEnumNdsSubTrees_Any( NULL,
  1028. tempStrPtr,
  1029. &dwClassType,
  1030. (LPNWWKSTA_CONTEXT_HANDLE) lphEnum ) )
  1031. ==NO_ERROR )
  1032. )
  1033. {
  1034. status = NO_ERROR;
  1035. }
  1036. else if (
  1037. ( slashCount < 4 ) &&
  1038. ( dwType & RESOURCETYPE_DISK ) &&
  1039. ( ( status = NwrOpenEnumNdsSubTrees_Disk( NULL,
  1040. tempStrPtr,
  1041. &dwClassType,
  1042. (LPNWWKSTA_CONTEXT_HANDLE) lphEnum ) )
  1043. ==NO_ERROR )
  1044. )
  1045. {
  1046. status = NO_ERROR;
  1047. }
  1048. else if (
  1049. ( slashCount < 4 ) &&
  1050. ( dwType & RESOURCETYPE_PRINT ) &&
  1051. ( ( status = NwrOpenEnumNdsSubTrees_Print( NULL,
  1052. tempStrPtr,
  1053. &dwClassType,
  1054. (LPNWWKSTA_CONTEXT_HANDLE) lphEnum ) )
  1055. ==NO_ERROR )
  1056. )
  1057. {
  1058. status = NO_ERROR;
  1059. }
  1060. else if (
  1061. (slashCount < 4
  1062. &&
  1063. (status == ERROR_NETWORK_ACCESS_DENIED
  1064. ||
  1065. status == ERROR_GEN_FAILURE
  1066. ||
  1067. status == ERROR_ACCESS_DENIED
  1068. ||
  1069. status == ERROR_BAD_NETPATH
  1070. ||
  1071. status == WN_BAD_NETNAME
  1072. ||
  1073. status == ERROR_INVALID_NAME))
  1074. ||
  1075. ( slashCount > 3 && status == NO_ERROR )
  1076. )
  1077. {
  1078. if (( status == ERROR_NETWORK_ACCESS_DENIED ) &&
  1079. ( dwClassType == CLASS_TYPE_NCP_SERVER ))
  1080. {
  1081. status = NO_ERROR;
  1082. isNdsUnc = TRUE;
  1083. IsEnumVolumes = TRUE;
  1084. }
  1085. else if ( ( status == ERROR_NETWORK_ACCESS_DENIED ) &&
  1086. ( ( dwClassType == CLASS_TYPE_VOLUME ) ||
  1087. ( dwClassType == CLASS_TYPE_DIRECTORY_MAP ) ) )
  1088. {
  1089. status = NO_ERROR;
  1090. isNdsUnc = TRUE;
  1091. IsEnumVolumes = FALSE;
  1092. }
  1093. else
  1094. {
  1095. //
  1096. // A third backslash means that we want to
  1097. // enumerate the directories.
  1098. //
  1099. if ( isNdsUnc && slashCount > 3 )
  1100. IsEnumVolumes = FALSE;
  1101. if ( !isNdsUnc && slashCount > 2 )
  1102. IsEnumVolumes = FALSE;
  1103. if ( lpNetResource->dwDisplayType == RESOURCEDISPLAYTYPE_SHARE )
  1104. IsEnumVolumes = FALSE;
  1105. }
  1106. status = NwpMapNameToUNC( tempStrPtr,
  1107. &pszRemoteName );
  1108. if ( status == NO_ERROR )
  1109. {
  1110. if ( IsEnumVolumes )
  1111. {
  1112. LPWSTR pszServerName = pszRemoteName;
  1113. // The following 10 lines are a hack to
  1114. // allow the provider to browse past the CN=<server>
  1115. // object in an NDS tree.
  1116. if ( slashCount == 3 && isNdsUnc == TRUE )
  1117. {
  1118. pszServerName = (LPWSTR)
  1119. NwpGetUncObjectName( pszRemoteName );
  1120. if ( pszServerName == NULL )
  1121. pszServerName = pszRemoteName;
  1122. }
  1123. else if ( dwUsage & RESOURCEUSAGE_ATTACHED )
  1124. {
  1125. #ifndef NT1057
  1126. // This is a bindery server.
  1127. // Return WN_NOT_AUTHENTICATED if
  1128. // we are not already attached so
  1129. // that clients ( explorer ) will
  1130. // do NPAddConnection3 to make
  1131. // a connection to the server.
  1132. BOOL fAttached;
  1133. BOOL fAuthenticated;
  1134. status = NwIsServerOrTreeAttached(
  1135. pszServerName + 2,
  1136. &fAttached,
  1137. &fAuthenticated );
  1138. if ( status != NO_ERROR )
  1139. break;
  1140. if ( !fAttached || !fAuthenticated)
  1141. {
  1142. // See if the server belongs to
  1143. // our provider.
  1144. status = NwrOpenEnumVolumes(
  1145. NULL,
  1146. pszServerName,
  1147. (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
  1148. if ( status == NO_ERROR )
  1149. {
  1150. // The server belongs to us.
  1151. // Close the handle and
  1152. // return not attached if
  1153. // callee passed in dwUsage
  1154. // flag:
  1155. // RESOURCEUSAGE_ATTACHED.
  1156. // Note: handle will be null
  1157. // after return from
  1158. // NwrCloseEnum
  1159. NwrCloseEnum( (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
  1160. status = WN_NOT_AUTHENTICATED;
  1161. }
  1162. else
  1163. {
  1164. // else the server does not
  1165. // belong to us.
  1166. status = WN_BAD_NETNAME;
  1167. }
  1168. break;
  1169. }
  1170. #endif
  1171. } // else, this is a bindery server and
  1172. // client does not care whether we
  1173. // are bindery authenticated.
  1174. if ( ( dwType == RESOURCETYPE_ANY ) ||
  1175. ( ( dwType & RESOURCETYPE_DISK ) &&
  1176. ( dwType & RESOURCETYPE_PRINT ) ) )
  1177. {
  1178. status = NwrOpenEnumVolumesQueues(
  1179. NULL,
  1180. pszServerName,
  1181. (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
  1182. }
  1183. else if ( dwType & RESOURCETYPE_DISK )
  1184. {
  1185. status = NwrOpenEnumVolumes(
  1186. NULL,
  1187. pszServerName,
  1188. (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
  1189. }
  1190. else if ( dwType & RESOURCETYPE_PRINT )
  1191. {
  1192. status = NwrOpenEnumQueues(
  1193. NULL,
  1194. pszServerName,
  1195. (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
  1196. }
  1197. }
  1198. else
  1199. {
  1200. LPWSTR CachedUserName = NULL ;
  1201. LPWSTR CachedPassword = NULL ;
  1202. #ifdef NT1057 // Make OpenEnum not interactive on SUR
  1203. (void) NwpRetrieveCachedCredentials( pszRemoteName,
  1204. &CachedUserName,
  1205. &CachedPassword );
  1206. #endif
  1207. status = NwrOpenEnumDirectories(
  1208. NULL,
  1209. pszRemoteName,
  1210. CachedUserName,
  1211. CachedPassword,
  1212. (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
  1213. #ifndef NT1057 // Make OpenEnum not interactive on SUR
  1214. if ( (status == ERROR_INVALID_PASSWORD)
  1215. || (status == ERROR_NO_SUCH_USER )
  1216. )
  1217. {
  1218. status = WN_NOT_AUTHENTICATED;
  1219. break;
  1220. }
  1221. #else
  1222. if ( CachedUserName )
  1223. {
  1224. (void) LocalFree( (HLOCAL) CachedUserName );
  1225. }
  1226. if ( CachedPassword )
  1227. {
  1228. RtlZeroMemory( CachedPassword,
  1229. wcslen(CachedPassword) *
  1230. sizeof( WCHAR ) );
  1231. (void) LocalFree( ( HLOCAL ) CachedPassword );
  1232. }
  1233. if ( ( status == ERROR_INVALID_PASSWORD ) ||
  1234. ( status == ERROR_NO_SUCH_USER ) )
  1235. {
  1236. LPWSTR UserName;
  1237. LPWSTR Password;
  1238. LPWSTR TmpPtr;
  1239. //
  1240. // Put up dialog to get username
  1241. // and password.
  1242. //
  1243. status = NwpGetUserCredential( NULL,
  1244. tempStrPtr,
  1245. status,
  1246. NULL,
  1247. &UserName,
  1248. &Password);
  1249. if ( status == NO_ERROR )
  1250. {
  1251. status = NwrOpenEnumDirectories(
  1252. NULL,
  1253. pszRemoteName,
  1254. UserName,
  1255. Password,
  1256. (LPNWWKSTA_CONTEXT_HANDLE) lphEnum );
  1257. if ( status == NO_ERROR )
  1258. {
  1259. status = NwpCacheCredentials(
  1260. pszRemoteName,
  1261. UserName,
  1262. Password ) ;
  1263. }
  1264. (void) LocalFree( UserName );
  1265. //
  1266. // Clear the password
  1267. //
  1268. TmpPtr = Password;
  1269. while ( *TmpPtr != 0 )
  1270. *TmpPtr++ = 0;
  1271. (void) LocalFree( Password );
  1272. }
  1273. else if ( status == ERROR_WINDOW_NOT_DIALOG )
  1274. {
  1275. //
  1276. // Caller is not a GUI app.
  1277. //
  1278. status = ERROR_INVALID_PASSWORD;
  1279. }
  1280. else if ( status == WN_CANCEL )
  1281. {
  1282. //
  1283. // Cancel was pressed but we still
  1284. // have to return success or MPR
  1285. // will popup the error. Return
  1286. // a bogus enum handle.
  1287. //
  1288. *lphEnum = (HANDLE) 0xFFFFFFFF;
  1289. status = NO_ERROR;
  1290. }
  1291. }
  1292. #endif
  1293. }
  1294. }
  1295. else
  1296. {
  1297. status = WN_BAD_NETNAME;
  1298. }
  1299. }
  1300. }
  1301. else
  1302. {
  1303. status = WN_BAD_VALUE;
  1304. }
  1305. if ( pszRemoteName != NULL )
  1306. LocalFree( (HLOCAL) pszRemoteName );
  1307. }
  1308. break;
  1309. default:
  1310. KdPrint(("NWPROVIDER: Invalid dwScope %lu\n", dwScope));
  1311. status = WN_BAD_VALUE;
  1312. } // end switch
  1313. }
  1314. else
  1315. {
  1316. status = WN_BAD_VALUE;
  1317. }
  1318. }
  1319. RpcExcept( 1 )
  1320. {
  1321. status = NwpMapRpcError(RpcExceptionCode());
  1322. }
  1323. RpcEndExcept
  1324. if ( status == ERROR_FILE_NOT_FOUND )
  1325. status = WN_BAD_NETNAME;
  1326. if ( status != NO_ERROR )
  1327. {
  1328. SetLastError( status );
  1329. }
  1330. return status;
  1331. }
  1332. DWORD
  1333. APIENTRY
  1334. NPEnumResource(
  1335. HANDLE hEnum,
  1336. LPDWORD lpcCount,
  1337. LPVOID lpBuffer,
  1338. LPDWORD lpBufferSize
  1339. )
  1340. /*++
  1341. Routine Description:
  1342. This function returns a lists of objects within the container
  1343. specified by the enumeration context handle.
  1344. Arguments:
  1345. hEnum - Supplies the resumable enumeration context handle.
  1346. NOTE: If this value is 0xFFFFFFFF, it is not a context
  1347. handle and this routine is required to return
  1348. WN_NO_MORE_ENTRIES. This hack is to handle the
  1349. case where the user cancelled out of the network
  1350. credential dialog on NwrOpenEnumDirectories and we
  1351. cannot return an error there or we generate an error
  1352. popup.
  1353. lpcCount - On input, supplies the number of entries to get.
  1354. On output, if NO_ERROR is returned, receives the number
  1355. of entries NETRESOURCE returned in lpBuffer.
  1356. lpBuffer - Receives an array of NETRESOURCE entries, each
  1357. entry describes an object within the container.
  1358. lpBufferSize - On input, supplies the size of lpBuffer in
  1359. bytes. On output, if WN_MORE_DATA is returned, receives
  1360. the number of bytes needed in the buffer to get the
  1361. next entry.
  1362. Return Value:
  1363. NO_ERROR - Successfully returned at least one entry.
  1364. WN_NO_MORE_ENTRIES - Reached the end of enumeration and nothing
  1365. is returned.
  1366. WN_MORE_DATA - lpBuffer is too small to even get one entry.
  1367. WN_BAD_HANDLE - The enumeration handle is invalid.
  1368. Other network errors.
  1369. --*/
  1370. {
  1371. DWORD status = NO_ERROR;
  1372. DWORD BytesNeeded = 0;
  1373. DWORD EntriesRead = 0;
  1374. #if DBG
  1375. IF_DEBUG(ENUM) {
  1376. KdPrint(("\nNWPROVAU: NPEnumResource\n"));
  1377. }
  1378. #endif
  1379. RpcTryExcept {
  1380. if (hEnum == (HANDLE) 0xFFFFFFFF) {
  1381. status = WN_NO_MORE_ENTRIES;
  1382. goto EndOfTry;
  1383. }
  1384. status = NwrEnum(
  1385. (NWWKSTA_CONTEXT_HANDLE) hEnum,
  1386. *lpcCount,
  1387. (LPBYTE) lpBuffer,
  1388. *lpBufferSize,
  1389. &BytesNeeded,
  1390. &EntriesRead
  1391. );
  1392. if (status == WN_MORE_DATA) {
  1393. //
  1394. // Output buffer too small to fit a single entry.
  1395. //
  1396. *lpBufferSize = BytesNeeded;
  1397. }
  1398. else if (status == NO_ERROR) {
  1399. *lpcCount = EntriesRead;
  1400. }
  1401. EndOfTry: ;
  1402. }
  1403. RpcExcept(1) {
  1404. status = NwpMapRpcError(RpcExceptionCode());
  1405. }
  1406. RpcEndExcept
  1407. if (status != NO_ERROR && status != WN_NO_MORE_ENTRIES) {
  1408. SetLastError(status);
  1409. }
  1410. else
  1411. {
  1412. //
  1413. // Convert offsets of strings to pointers
  1414. //
  1415. if (EntriesRead > 0) {
  1416. DWORD i;
  1417. LPNETRESOURCEW NetR;
  1418. NetR = lpBuffer;
  1419. for (i = 0; i < EntriesRead; i++, NetR++) {
  1420. if (NetR->lpLocalName != NULL) {
  1421. NetR->lpLocalName = (LPWSTR) ((DWORD_PTR) lpBuffer +
  1422. (DWORD_PTR) NetR->lpLocalName);
  1423. }
  1424. NetR->lpRemoteName = (LPWSTR) ((DWORD_PTR) lpBuffer +
  1425. (DWORD_PTR) NetR->lpRemoteName);
  1426. if (NetR->lpComment != NULL) {
  1427. NetR->lpComment = (LPWSTR) ((DWORD_PTR) lpBuffer +
  1428. (DWORD_PTR) NetR->lpComment);
  1429. }
  1430. if (NetR->lpProvider != NULL) {
  1431. NetR->lpProvider = (LPWSTR) ((DWORD_PTR) lpBuffer +
  1432. (DWORD_PTR) NetR->lpProvider);
  1433. }
  1434. }
  1435. }
  1436. }
  1437. return status;
  1438. }
  1439. DWORD
  1440. APIENTRY
  1441. NPGetResourceInformation(
  1442. LPNETRESOURCEW lpNetResource,
  1443. LPVOID lpBuffer,
  1444. LPDWORD cbBuffer,
  1445. LPWSTR * lplpSystem
  1446. )
  1447. /*++
  1448. Routine Description:
  1449. This function returns an object which details information
  1450. about a specified network resource.
  1451. Arguments:
  1452. lpNetResource - This specifies the network resource for which the
  1453. information is required. The lpRemoteName field of the NETRESOURCE
  1454. specifies the remote name of the network resource whose information
  1455. is required. If the calling program knows the values for the
  1456. lpProvider and dwType fields, then it should fill them in, otherwise,
  1457. it should set them to NULL. All other fields in the NETRESOURCE are
  1458. ignored and are not initialized.
  1459. lpBuffer - A pointer to the buffer to receive the result, which is
  1460. returned as a single NETRESOURCE entry representing the parent
  1461. resource. The lpRemoteName, lpProvider, dwType, and dwUsage fields
  1462. are returned, all other fields being set to NULL. The remote name
  1463. returned should be in the same syntax as that returned from an
  1464. enumeration, so that the caller can do a case sensitive string
  1465. compare to determine whether an enumerated resource is this resource.
  1466. If the provider owns a parent of the network resource, (in other
  1467. words is known to be the correct network to respond to this request),
  1468. then lpProvider should be filled in with a non-null entry. If it is
  1469. known that a network owns a parent of the resource, but that the
  1470. resource itself is not valid, then lpProvider is returned as a
  1471. non-null value together with a return status of WN_BAD_VALUE. dwScope
  1472. is returned as RESOURCE_CONTEXT if the network resource is part of
  1473. the user's network context, otherwise it is returned as zero.
  1474. cbBuffer - This specifies the size in bytes of the buffer passed to the
  1475. function call. If the result is WN_MORE_DATA, this will contain the
  1476. buffer size required (in bytes) to hold the NETRESOURCE information.
  1477. lplpSystem - Returned pointer to a string in the buffer pointed to by
  1478. lpBuffer that specifies the part of the resource that is accessed
  1479. through resource type specific system APIs rather than WNet APIs.
  1480. For example, if the input remote resource name was
  1481. "\\server\share\dir", then lpRemoteName is returned pointing to
  1482. "\\server\share" and lplpSystem points to "\dir", both strings
  1483. being stored in the buffer pointed to by lpBuffer.
  1484. Return Value:
  1485. WN_SUCCESS - If the call is successful.
  1486. WN_MORE_DATA - If input buffer is too small.
  1487. WN_BAD_VALUE - Invalid dwScope or dwUsage or dwType, or bad combination
  1488. of parameters is specified (e.g. lpRemoteName does not correspond
  1489. to dwType).
  1490. WN_BAD_NETNAME - The resource is not recognized by this provider.
  1491. --*/
  1492. {
  1493. DWORD status;
  1494. LPWSTR pszRemoteName = NULL;
  1495. DWORD BytesNeeded = 0;
  1496. DWORD SystemOffset = 0;
  1497. *lplpSystem = NULL;
  1498. status = NwpMapNameToUNC( lpNetResource->lpRemoteName, &pszRemoteName );
  1499. if (status != NO_ERROR)
  1500. {
  1501. SetLastError(status);
  1502. return status;
  1503. }
  1504. #if DBG
  1505. IF_DEBUG(CONNECT)
  1506. {
  1507. KdPrint(("\nNWPROVAU: NPGetResourceInformation %ws\n", pszRemoteName));
  1508. }
  1509. #endif
  1510. RpcTryExcept
  1511. {
  1512. if (lpNetResource->dwType != RESOURCETYPE_ANY &&
  1513. lpNetResource->dwType != RESOURCETYPE_DISK &&
  1514. lpNetResource->dwType != RESOURCETYPE_PRINT)
  1515. {
  1516. status = WN_BAD_VALUE;
  1517. }
  1518. else
  1519. {
  1520. status = NwrGetResourceInformation(
  1521. NULL,
  1522. pszRemoteName,
  1523. lpNetResource->dwType,
  1524. (LPBYTE) lpBuffer,
  1525. *cbBuffer,
  1526. &BytesNeeded,
  1527. &SystemOffset
  1528. );
  1529. if (status == WN_MORE_DATA)
  1530. {
  1531. //
  1532. // Output buffer too small.
  1533. //
  1534. *cbBuffer = BytesNeeded;
  1535. }
  1536. }
  1537. }
  1538. RpcExcept(1)
  1539. {
  1540. status = NwpMapRpcError(RpcExceptionCode());
  1541. }
  1542. RpcEndExcept
  1543. if ( pszRemoteName )
  1544. LocalFree( (HLOCAL) pszRemoteName );
  1545. if (status != NO_ERROR)
  1546. {
  1547. SetLastError(status);
  1548. }
  1549. else
  1550. {
  1551. //
  1552. // Convert offsets of strings to pointers
  1553. //
  1554. DWORD i;
  1555. LPNETRESOURCEW NetR = lpBuffer;
  1556. if (NetR->lpLocalName != NULL)
  1557. {
  1558. NetR->lpLocalName = (LPWSTR) ((DWORD_PTR) lpBuffer +
  1559. (DWORD_PTR) NetR->lpLocalName);
  1560. }
  1561. NetR->lpRemoteName = (LPWSTR) ((DWORD_PTR) lpBuffer +
  1562. (DWORD_PTR) NetR->lpRemoteName);
  1563. if (NetR->lpComment != NULL)
  1564. {
  1565. NetR->lpComment = (LPWSTR) ((DWORD_PTR) lpBuffer +
  1566. (DWORD_PTR) NetR->lpComment);
  1567. }
  1568. if (NetR->lpProvider != NULL)
  1569. {
  1570. NetR->lpProvider = (LPWSTR) ((DWORD_PTR) lpBuffer +
  1571. (DWORD_PTR) NetR->lpProvider);
  1572. }
  1573. if (SystemOffset != 0)
  1574. {
  1575. *lplpSystem = (LPWSTR) ((DWORD_PTR) lpBuffer + SystemOffset);
  1576. }
  1577. }
  1578. return status;
  1579. }
  1580. DWORD
  1581. APIENTRY
  1582. NPGetResourceParent(
  1583. LPNETRESOURCEW lpNetResource,
  1584. LPVOID lpBuffer,
  1585. LPDWORD cbBuffer
  1586. )
  1587. /*++
  1588. Routine Description:
  1589. This function returns an object which details information
  1590. about the parent of a specified network resource.
  1591. Arguments:
  1592. lpNetResource - This specifies the network resource for which the
  1593. parent name is required. The NETRESOURCE could have been obtained via
  1594. previous NPEnumResource, or constructed by the caller. The lpRemoteName
  1595. field of the NETRESOURCE specifies the remote name of the network
  1596. resouce whose parent name is required. If the calling program knows
  1597. the values for the lpProvider and dwType fields, then it can fill
  1598. them in, otherwise, they are set to NULL. If the lpProvider field is
  1599. not NULL, then the network provider DLL can assume that the resource
  1600. is owned by its network, but if it is NULL, then it must assume
  1601. that the resource could be for some other network and do whatever
  1602. checking is neccessary to ensure that the result returned is accurate.
  1603. For example, if being asked for the parent of a server, and the server
  1604. is not part of a workgroup, the the network provider DLL should check
  1605. to ensure that the server is part of its network and, if so, return
  1606. its provider name. All other fields in the NETRESOURCE are ignored and
  1607. are not initialized.
  1608. lpBuffer - A pointer to the buffer to receive the result, which is
  1609. returned as a single NETRESOURCE entry representing the parent
  1610. resource. The lpRemoteName, lpProvider, dwType, and dwUsage fields
  1611. are returned, all other fields being set to NULL. lpProvider should
  1612. be set to NULL if the provider has only done a syntactic check (i.e.
  1613. does not know that the resource is specific to its network). If the
  1614. provider owns a parent of the network resource, (in other words is
  1615. known to be the correct network to respond to this request), then
  1616. lpProvider should be filled in with a non-null entry, even if the
  1617. return is WN_BAD_VALUE. The remote name returned should be in the
  1618. same syntax as that returned from an enumeration, so that the caller
  1619. can do a case sensitive string compare to determine whether an
  1620. enumerated resource is this resource. If a resource has no browse
  1621. parent on the network, the lpRemoteName is returned as NULL. The
  1622. RESOURCEUSAGE_CONNECTABLE value in the dwUsage field does not
  1623. indicate that the resource can currently be connected to, but that
  1624. the resource is connectable when it is available on the network.
  1625. cbBuffer - This specifies the size in bytes of the buffer passed to the
  1626. function call. If the result is WN_MORE_DATA, this will contain the
  1627. buffer size required (in bytes) to hold the NETRESOURCE information.
  1628. Return Value:
  1629. WN_SUCCESS - If the call is successful.
  1630. WN_MORE_DATA - If input buffer is too small.
  1631. WN_BAD_VALUE - Invalid dwScope or dwUsage or dwType, or bad combination
  1632. of parameters is specified (e.g. lpRemoteName does not correspond
  1633. to dwType).
  1634. --*/
  1635. {
  1636. DWORD status;
  1637. LPWSTR pszRemoteName = NULL;
  1638. DWORD BytesNeeded = 0;
  1639. status = NwpMapNameToUNC( lpNetResource->lpRemoteName, &pszRemoteName );
  1640. if (status != NO_ERROR)
  1641. {
  1642. SetLastError(status);
  1643. return status;
  1644. }
  1645. #if DBG
  1646. IF_DEBUG(CONNECT)
  1647. {
  1648. KdPrint(("\nNWPROVAU: NPGetResourceParent %ws\n", pszRemoteName));
  1649. }
  1650. #endif
  1651. RpcTryExcept
  1652. {
  1653. if (lpNetResource->dwType != RESOURCETYPE_ANY &&
  1654. lpNetResource->dwType != RESOURCETYPE_DISK &&
  1655. lpNetResource->dwType != RESOURCETYPE_PRINT)
  1656. {
  1657. status = WN_BAD_VALUE;
  1658. }
  1659. else
  1660. {
  1661. status = NwrGetResourceParent(
  1662. NULL,
  1663. pszRemoteName,
  1664. lpNetResource->dwType,
  1665. (LPBYTE) lpBuffer,
  1666. *cbBuffer,
  1667. &BytesNeeded
  1668. );
  1669. if (status == WN_MORE_DATA)
  1670. {
  1671. //
  1672. // Output buffer too small.
  1673. //
  1674. *cbBuffer = BytesNeeded;
  1675. }
  1676. }
  1677. }
  1678. RpcExcept(1)
  1679. {
  1680. status = NwpMapRpcError(RpcExceptionCode());
  1681. }
  1682. RpcEndExcept
  1683. if ( pszRemoteName )
  1684. LocalFree( (HLOCAL) pszRemoteName );
  1685. if (status != NO_ERROR)
  1686. {
  1687. SetLastError(status);
  1688. }
  1689. else
  1690. {
  1691. //
  1692. // Convert offsets of strings to pointers
  1693. //
  1694. DWORD i;
  1695. LPNETRESOURCEW NetR = lpBuffer;
  1696. if (NetR->lpLocalName != NULL)
  1697. {
  1698. NetR->lpLocalName = (LPWSTR) ((DWORD_PTR) lpBuffer +
  1699. (DWORD_PTR) NetR->lpLocalName);
  1700. }
  1701. NetR->lpRemoteName = (LPWSTR) ((DWORD_PTR) lpBuffer +
  1702. (DWORD_PTR) NetR->lpRemoteName);
  1703. if (NetR->lpComment != NULL)
  1704. {
  1705. NetR->lpComment = (LPWSTR) ((DWORD_PTR) lpBuffer +
  1706. (DWORD_PTR) NetR->lpComment);
  1707. }
  1708. if (NetR->lpProvider != NULL)
  1709. {
  1710. NetR->lpProvider = (LPWSTR) ((DWORD_PTR) lpBuffer +
  1711. (DWORD_PTR) NetR->lpProvider);
  1712. }
  1713. }
  1714. return status;
  1715. }
  1716. DWORD
  1717. APIENTRY
  1718. NwEnumConnections(
  1719. HANDLE hEnum,
  1720. LPDWORD lpcCount,
  1721. LPVOID lpBuffer,
  1722. LPDWORD lpBufferSize,
  1723. BOOL fImplicitConnections
  1724. )
  1725. /*++
  1726. Routine Description:
  1727. This function returns a lists of connections.
  1728. Arguments:
  1729. hEnum - Supplies the resumable enumeration context handle.
  1730. NOTE: If this value is 0xFFFFFFFF, it is not a context
  1731. handle and this routine is required to return
  1732. WN_NO_MORE_ENTRIES. This hack is to handle the
  1733. case where the user cancelled out of the network
  1734. credential dialog on NwrOpenEnumDirectories and we
  1735. cannot return an error there or we generate an error
  1736. popup.
  1737. lpcCount - On input, supplies the number of entries to get.
  1738. On output, if NO_ERROR is returned, receives the number
  1739. of entries NETRESOURCE returned in lpBuffer.
  1740. lpBuffer - Receives an array of NETRESOURCE entries, each
  1741. entry describes an object within the container.
  1742. lpBufferSize - On input, supplies the size of lpBuffer in
  1743. bytes. On output, if WN_MORE_DATA is returned, receives
  1744. the number of bytes needed in the buffer to get the
  1745. next entry.
  1746. fImplicitConnections - TRUE is we also want all implicit connections,
  1747. FALSE otherwise.
  1748. Return Value:
  1749. NO_ERROR - Successfully returned at least one entry.
  1750. WN_NO_MORE_ENTRIES - Reached the end of enumeration and nothing
  1751. is returned.
  1752. WN_MORE_DATA - lpBuffer is too small to even get one entry.
  1753. WN_BAD_HANDLE - The enumeration handle is invalid.
  1754. Other network errors.
  1755. --*/
  1756. {
  1757. DWORD status = NO_ERROR;
  1758. DWORD BytesNeeded = 0;
  1759. DWORD EntriesRead = 0;
  1760. #if DBG
  1761. IF_DEBUG(ENUM) {
  1762. KdPrint(("\nNWPROVAU: NPEnumResource\n"));
  1763. }
  1764. #endif
  1765. RpcTryExcept {
  1766. if (hEnum == (HANDLE) 0xFFFFFFFF) {
  1767. status = WN_NO_MORE_ENTRIES;
  1768. goto EndOfTry;
  1769. }
  1770. status = NwrEnumConnections(
  1771. (NWWKSTA_CONTEXT_HANDLE) hEnum,
  1772. *lpcCount,
  1773. (LPBYTE) lpBuffer,
  1774. *lpBufferSize,
  1775. &BytesNeeded,
  1776. &EntriesRead,
  1777. fImplicitConnections
  1778. );
  1779. if (status == WN_MORE_DATA) {
  1780. //
  1781. // Output buffer too small to fit a single entry.
  1782. //
  1783. *lpBufferSize = BytesNeeded;
  1784. }
  1785. else if (status == NO_ERROR) {
  1786. *lpcCount = EntriesRead;
  1787. }
  1788. EndOfTry: ;
  1789. }
  1790. RpcExcept(1) {
  1791. status = NwpMapRpcError(RpcExceptionCode());
  1792. }
  1793. RpcEndExcept
  1794. if (status != NO_ERROR && status != WN_NO_MORE_ENTRIES) {
  1795. SetLastError(status);
  1796. }
  1797. //
  1798. // Convert offsets of strings to pointers
  1799. //
  1800. if (EntriesRead > 0) {
  1801. DWORD i;
  1802. LPNETRESOURCEW NetR;
  1803. NetR = lpBuffer;
  1804. for (i = 0; i < EntriesRead; i++, NetR++) {
  1805. if (NetR->lpLocalName != NULL) {
  1806. NetR->lpLocalName = (LPWSTR) ((DWORD_PTR) lpBuffer +
  1807. (DWORD_PTR) NetR->lpLocalName);
  1808. }
  1809. NetR->lpRemoteName = (LPWSTR) ((DWORD_PTR) lpBuffer +
  1810. (DWORD_PTR) NetR->lpRemoteName);
  1811. if (NetR->lpComment != NULL) {
  1812. NetR->lpComment = (LPWSTR) ((DWORD_PTR) lpBuffer +
  1813. (DWORD_PTR) NetR->lpComment);
  1814. }
  1815. if (NetR->lpProvider != NULL) {
  1816. NetR->lpProvider = (LPWSTR) ((DWORD_PTR) lpBuffer +
  1817. (DWORD_PTR) NetR->lpProvider);
  1818. }
  1819. }
  1820. }
  1821. return status;
  1822. }
  1823. DWORD
  1824. APIENTRY
  1825. NPCloseEnum(
  1826. HANDLE hEnum
  1827. )
  1828. /*++
  1829. Routine Description:
  1830. This function closes the enumeration context handle.
  1831. Arguments:
  1832. hEnum - Supplies the enumeration context handle.
  1833. NOTE: If this value is 0xFFFFFFFF, it is not a context
  1834. handle. Just return success.
  1835. Return Value:
  1836. NO_ERROR - Successfully returned at least one entry.
  1837. WN_BAD_HANDLE - The enumeration handle is invalid.
  1838. --*/
  1839. {
  1840. DWORD status = NO_ERROR;
  1841. #if DBG
  1842. IF_DEBUG(ENUM) {
  1843. KdPrint(("\nNWPROVAU: NPCloseEnum\n"));
  1844. }
  1845. #endif
  1846. RpcTryExcept
  1847. {
  1848. if (hEnum == (HANDLE) 0xFFFFFFFF) {
  1849. status = NO_ERROR;
  1850. }
  1851. else {
  1852. status = NwrCloseEnum(
  1853. (LPNWWKSTA_CONTEXT_HANDLE) &hEnum
  1854. );
  1855. }
  1856. }
  1857. RpcExcept(1) {
  1858. status = NwpMapRpcError(RpcExceptionCode());
  1859. }
  1860. RpcEndExcept
  1861. if (status != NO_ERROR) {
  1862. SetLastError(status);
  1863. }
  1864. return status;
  1865. }
  1866. DWORD
  1867. APIENTRY
  1868. NPFormatNetworkName(
  1869. LPWSTR lpRemoteName,
  1870. LPWSTR lpFormattedName,
  1871. LPDWORD lpnLength,
  1872. DWORD dwFlags,
  1873. DWORD dwAveCharPerLine
  1874. )
  1875. /*++
  1876. Routine Description:
  1877. This function takes a fully-qualified UNC name and formats it
  1878. into a shorter form for display. Only the name of the object
  1879. within the container is returned for display.
  1880. We only support formatting of the remote resource name to the
  1881. abbreviated form for display during enumeration where the container
  1882. name is displayed prior to the object within it.
  1883. Arguments:
  1884. lpRemoteName - Supplies the fully-qualified UNC name.
  1885. lpFormatedName - Output buffer to receive the formatted name.
  1886. lpnLength - On input, supplies the length of the lpFormattedName
  1887. buffer in characters. On output, if WN_MORE_DATA is returned,
  1888. receives the length in number of characters required of the
  1889. output buffer to hold the formatted name.
  1890. dwFlags - Supplies a bitwise set of flags indicating the type
  1891. of formatting required on lpRemoteName.
  1892. dwAveCharPerLine - Ignored.
  1893. Return Value:
  1894. NO_ERROR - Successfully returned at least one entry.
  1895. WN_MORE_DATA - lpFormattedName buffer is too small.
  1896. WN_BAD_VALUE - lpRemoteName is NULL.
  1897. ERROR_NOT_SUPPORTED - dwFlags that does not contain the
  1898. WNFMT_INENUM bit.
  1899. --*/
  1900. {
  1901. DWORD status = NO_ERROR;
  1902. LPWSTR NextBackSlash;
  1903. LPWSTR Source;
  1904. DWORD SourceLen;
  1905. #if DBG
  1906. IF_DEBUG(OTHER)
  1907. KdPrint(("\nNWPROVAU: NPFormatNetworkName\n"));
  1908. #endif
  1909. if (lpRemoteName == NULL)
  1910. {
  1911. status = WN_BAD_VALUE;
  1912. goto CleanExit;
  1913. }
  1914. if (dwFlags & WNFMT_INENUM)
  1915. {
  1916. WORD i;
  1917. WORD length = (WORD) wcslen( lpRemoteName );
  1918. WORD slashCount = 0;
  1919. WORD dotCount = 0;
  1920. WORD Start = 0;
  1921. WORD End = length;
  1922. BOOL isNdsUnc = FALSE;
  1923. BOOL couldBeNdsUnc = FALSE;
  1924. if ( lpRemoteName[0] == L' ' )
  1925. couldBeNdsUnc = TRUE;
  1926. for ( i = 0; i < length; i++ )
  1927. {
  1928. if ( lpRemoteName[i] == L'\\' )
  1929. {
  1930. slashCount++;
  1931. if ( i + 1 < length )
  1932. {
  1933. Start = i + 1;
  1934. }
  1935. }
  1936. if ( couldBeNdsUnc &&
  1937. ( ( lpRemoteName[i] == L'.' ) ||
  1938. ( lpRemoteName[i] == L'=' ) ) )
  1939. isNdsUnc = TRUE;
  1940. if ( dotCount < 1 && isNdsUnc && lpRemoteName[i] == L'.' )
  1941. {
  1942. End = i - 1;
  1943. dotCount++;
  1944. }
  1945. }
  1946. if ( i > length )
  1947. End = length - 1;
  1948. if ( slashCount > 3 || ( isNdsUnc != TRUE && slashCount != 3 && dotCount == 0 ) )
  1949. End = i - 1;
  1950. Source = &lpRemoteName[Start];
  1951. SourceLen = End - Start + 1;
  1952. if ( SourceLen + 1 > *lpnLength )
  1953. {
  1954. *lpnLength = SourceLen + 1;
  1955. status = WN_MORE_DATA;
  1956. }
  1957. else
  1958. {
  1959. wcsncpy( lpFormattedName, Source, SourceLen );
  1960. lpFormattedName[SourceLen] = 0x00000000;
  1961. status = NO_ERROR;
  1962. }
  1963. }
  1964. else if ( dwFlags & WNFMT_MULTILINE )
  1965. {
  1966. DWORD i, j, k = 0;
  1967. DWORD nLastBackSlash = 0;
  1968. DWORD BytesNeeded = ( wcslen( lpRemoteName ) + 1 +
  1969. 2 * wcslen( lpRemoteName ) / dwAveCharPerLine
  1970. ) * sizeof( WCHAR);
  1971. if ( *lpnLength < (BytesNeeded/sizeof(WCHAR)) )
  1972. {
  1973. *lpnLength = BytesNeeded/sizeof(WCHAR);
  1974. status = WN_MORE_DATA;
  1975. goto CleanExit;
  1976. }
  1977. for ( i = 0, j = 0; lpRemoteName[i] != 0; i++, j++ )
  1978. {
  1979. if ( lpRemoteName[i] == L'\\' )
  1980. nLastBackSlash = i;
  1981. if ( k == dwAveCharPerLine )
  1982. {
  1983. if ( lpRemoteName[i] != L'\\' )
  1984. {
  1985. DWORD m, n;
  1986. for ( n = nLastBackSlash, m = ++j ; n <= i ; n++, m-- )
  1987. {
  1988. lpFormattedName[m] = lpFormattedName[m-1];
  1989. }
  1990. lpFormattedName[m] = L'\n';
  1991. k = i - nLastBackSlash - 1;
  1992. }
  1993. else
  1994. {
  1995. lpFormattedName[j++] = L'\n';
  1996. k = 0;
  1997. }
  1998. }
  1999. lpFormattedName[j] = lpRemoteName[i];
  2000. k++;
  2001. }
  2002. lpFormattedName[j] = 0;
  2003. }
  2004. else if ( dwFlags & WNFMT_ABBREVIATED )
  2005. {
  2006. //
  2007. // we dont support abbreviated form for now because we look bad
  2008. // in comdlg (fileopen) if we do.
  2009. //
  2010. DWORD nLength;
  2011. nLength = wcslen( lpRemoteName ) + 1 ;
  2012. if (nLength > *lpnLength)
  2013. {
  2014. *lpnLength = nLength;
  2015. status = WN_MORE_DATA;
  2016. goto CleanExit;
  2017. }
  2018. else
  2019. {
  2020. wcscpy( lpFormattedName, lpRemoteName );
  2021. }
  2022. #if 0
  2023. DWORD i, j, k;
  2024. DWORD BytesNeeded = dwAveCharPerLine * sizeof( WCHAR);
  2025. DWORD nLength;
  2026. if ( *lpnLength < BytesNeeded )
  2027. {
  2028. *lpnLength = BytesNeeded;
  2029. status = WN_MORE_DATA;
  2030. goto CleanExit;
  2031. }
  2032. nLength = wcslen( lpRemoteName );
  2033. if ( ( nLength + 1) <= dwAveCharPerLine )
  2034. {
  2035. wcscpy( lpFormattedName, lpRemoteName );
  2036. }
  2037. else
  2038. {
  2039. lpFormattedName[0] = lpRemoteName[0];
  2040. lpFormattedName[1] = lpRemoteName[1];
  2041. for ( i = 2; lpRemoteName[i] != L'\\'; i++ )
  2042. lpFormattedName[i] = lpRemoteName[i];
  2043. for ( j = dwAveCharPerLine-1, k = nLength; j >= (i+3); j--, k-- )
  2044. {
  2045. lpFormattedName[j] = lpRemoteName[k];
  2046. if ( lpRemoteName[k] == L'\\' )
  2047. {
  2048. j--;
  2049. break;
  2050. }
  2051. }
  2052. lpFormattedName[j] = lpFormattedName[j-1] = lpFormattedName[j-2] = L'.';
  2053. for ( k = i; k < (j-2); k++ )
  2054. lpFormattedName[k] = lpRemoteName[k];
  2055. }
  2056. #endif
  2057. }
  2058. else // some unknown flags
  2059. {
  2060. status = ERROR_NOT_SUPPORTED;
  2061. }
  2062. CleanExit:
  2063. if (status != NO_ERROR)
  2064. SetLastError(status);
  2065. return status;
  2066. }
  2067. STATIC
  2068. BOOL
  2069. NwpWorkstationStarted(
  2070. VOID
  2071. )
  2072. /*++
  2073. Routine Description:
  2074. This function queries the service controller to see if the
  2075. NetWare workstation service has started. If in doubt, it returns
  2076. FALSE.
  2077. Arguments:
  2078. None.
  2079. Return Value:
  2080. Returns TRUE if the NetWare workstation service has started,
  2081. FALSE otherwise.
  2082. --*/
  2083. {
  2084. SC_HANDLE ScManager;
  2085. SC_HANDLE Service;
  2086. SERVICE_STATUS ServiceStatus;
  2087. BOOL IsStarted = FALSE;
  2088. ScManager = OpenSCManagerW(
  2089. NULL,
  2090. NULL,
  2091. SC_MANAGER_CONNECT
  2092. );
  2093. if (ScManager == NULL) {
  2094. return FALSE;
  2095. }
  2096. Service = OpenServiceW(
  2097. ScManager,
  2098. NW_WORKSTATION_SERVICE,
  2099. SERVICE_QUERY_STATUS
  2100. );
  2101. if (Service == NULL) {
  2102. CloseServiceHandle(ScManager);
  2103. return FALSE;
  2104. }
  2105. if (! QueryServiceStatus(Service, &ServiceStatus)) {
  2106. CloseServiceHandle(ScManager);
  2107. CloseServiceHandle(Service);
  2108. return FALSE;
  2109. }
  2110. if ( (ServiceStatus.dwCurrentState == SERVICE_RUNNING) ||
  2111. (ServiceStatus.dwCurrentState == SERVICE_CONTINUE_PENDING) ||
  2112. (ServiceStatus.dwCurrentState == SERVICE_PAUSE_PENDING) ||
  2113. (ServiceStatus.dwCurrentState == SERVICE_PAUSED) ) {
  2114. IsStarted = TRUE;
  2115. }
  2116. CloseServiceHandle(ScManager);
  2117. CloseServiceHandle(Service);
  2118. return IsStarted;
  2119. }
  2120. DWORD
  2121. NwpMapNameToUNC(
  2122. IN LPWSTR pszName,
  2123. OUT LPWSTR *ppszUNC
  2124. )
  2125. /*++
  2126. Routine Description:
  2127. This routine validates the given name as a netwarepath or UNC path.
  2128. If it is a netware path, this routine will convert the
  2129. Netware path name to UNC name.
  2130. Arguments:
  2131. pszName - Supplies the netware name or UNC name
  2132. ppszUNC - Points to the converted UNC name
  2133. Return Value:
  2134. NO_ERROR or the error that occurred.
  2135. --*/
  2136. {
  2137. DWORD err = NO_ERROR;
  2138. LPWSTR pszSrc = pszName;
  2139. LPWSTR pszDest;
  2140. BOOL fSlash = FALSE;
  2141. BOOL fColon = FALSE;
  2142. DWORD nServerLen = 0;
  2143. DWORD nVolLen = 0;
  2144. BOOL fFirstToken = TRUE;
  2145. *ppszUNC = NULL;
  2146. //
  2147. // The name cannot be NULL or empty string
  2148. //
  2149. if ( pszName == NULL || *pszName == 0)
  2150. return WN_BAD_NETNAME;
  2151. #if DBG
  2152. IF_DEBUG(CONNECT)
  2153. KdPrint(("NwpMapNameToUNC: Source = %ws\n", pszName ));
  2154. #endif
  2155. //
  2156. // Get rid of the <space> if a NDS tree name ...
  2157. //
  2158. if ( pszName[0] == L' ' &&
  2159. pszName[1] == L'\\' &&
  2160. pszName[2] == L'\\' )
  2161. pszName = &pszName[1];
  2162. //
  2163. // Check if the given name is a valid UNC name
  2164. //
  2165. err = NwLibCanonRemoteName( NULL, // "\\Server" is valid UNC path
  2166. pszName,
  2167. ppszUNC,
  2168. NULL );
  2169. //
  2170. // The given name is a valid UNC name, so return success!
  2171. //
  2172. if ( err == NO_ERROR )
  2173. return err;
  2174. //
  2175. // Allocate the buffer to store the mapped UNC name
  2176. // We allocate 3 extra characters, two for the backslashes in front
  2177. // and one for the ease of parsing below.
  2178. //
  2179. if ((*ppszUNC = (LPVOID) LocalAlloc(
  2180. LMEM_ZEROINIT,
  2181. (wcslen( pszName) + 4) * sizeof( WCHAR)
  2182. )) == NULL )
  2183. {
  2184. return ERROR_NOT_ENOUGH_MEMORY;
  2185. }
  2186. wcscpy( *ppszUNC, L"\\\\" );
  2187. pszDest = *ppszUNC + 2; // Skip past two backslashes
  2188. //
  2189. // Parse the given string and put the converted string into *ppszUNC
  2190. // In the converted string, we will substitute 0 for all slashes
  2191. // for the time being.
  2192. //
  2193. for ( ; *pszSrc != 0; pszSrc++ )
  2194. {
  2195. if ( ( *pszSrc == L'/' )
  2196. || ( *pszSrc == L'\\' )
  2197. )
  2198. {
  2199. //
  2200. // Two consecutive backslashes are bad
  2201. //
  2202. if ( (*(pszSrc+1) == L'/') || (*(pszSrc+1) == L'\\'))
  2203. {
  2204. LocalFree( *ppszUNC );
  2205. *ppszUNC = NULL;
  2206. return WN_BAD_NETNAME;
  2207. }
  2208. if ( !fSlash )
  2209. fSlash = TRUE;
  2210. *pszDest++ = 0;
  2211. }
  2212. else if ( (*pszSrc == L':') && fSlash && !fColon )
  2213. {
  2214. fColon = TRUE;
  2215. if ( *(pszSrc+1) != 0 )
  2216. *pszDest++ = 0;
  2217. }
  2218. else
  2219. {
  2220. *pszDest++ = *pszSrc;
  2221. if (( fSlash ) && ( !fColon))
  2222. nVolLen++;
  2223. else if ( !fSlash )
  2224. nServerLen++;
  2225. }
  2226. }
  2227. //
  2228. // Note: *ppszUNC is already terminated with two '\0' because we initialized
  2229. // the whole buffer to zero.
  2230. //
  2231. if ( ( nServerLen == 0 )
  2232. || ( fSlash && nVolLen == 0 )
  2233. || ( fSlash && nVolLen != 0 && !fColon )
  2234. )
  2235. {
  2236. LocalFree( *ppszUNC );
  2237. *ppszUNC = NULL;
  2238. return WN_BAD_NETNAME;
  2239. }
  2240. //
  2241. // At this point, we know the name is a valid Netware syntax
  2242. // i.e. SERVER[/VOL:/dir]
  2243. // We now need to validate that all the characters used in the
  2244. // servername, volume, directory are valid characters
  2245. //
  2246. pszDest = *ppszUNC + 2; // Skip past the first two backslashes
  2247. while ( *pszDest != 0 )
  2248. {
  2249. DWORD nLen = wcslen( pszDest );
  2250. if ( ( fFirstToken && !IS_VALID_SERVER_TOKEN( pszDest, nLen ))
  2251. || ( !fFirstToken && !IS_VALID_TOKEN( pszDest, nLen ))
  2252. )
  2253. {
  2254. LocalFree( *ppszUNC );
  2255. *ppszUNC = NULL;
  2256. return WN_BAD_NETNAME;
  2257. }
  2258. fFirstToken = FALSE;
  2259. pszDest += nLen + 1;
  2260. }
  2261. //
  2262. // The netware name is valid! Convert 0 back to backslash in
  2263. // converted string.
  2264. //
  2265. pszDest = *ppszUNC + 2; // Skip past the first two backslashes
  2266. while ( *pszDest != 0 )
  2267. {
  2268. if ( (*(pszDest+1) == 0 ) && (*(pszDest+2) != 0 ) )
  2269. {
  2270. *(pszDest+1) = L'\\';
  2271. }
  2272. pszDest++;
  2273. }
  2274. #if DBG
  2275. IF_DEBUG(CONNECT)
  2276. KdPrint(("NwpMapNameToUNC: Destination = %ws\n", *ppszUNC ));
  2277. #endif
  2278. return NO_ERROR;
  2279. }
  2280. STATIC
  2281. VOID
  2282. NwpGetUncInfo(
  2283. IN LPWSTR lpstrUnc,
  2284. OUT WORD * slashCount,
  2285. OUT BOOL * isNdsUnc
  2286. )
  2287. {
  2288. WORD i;
  2289. WORD length = (WORD) wcslen( lpstrUnc );
  2290. *isNdsUnc = FALSE;
  2291. *slashCount = 0;
  2292. for ( i = 0; i < length; i++ )
  2293. {
  2294. if ( ( lpstrUnc[i] == L'.' ) && ( *slashCount == 3 ) )
  2295. {
  2296. *isNdsUnc = TRUE;
  2297. }
  2298. if ( lpstrUnc[i] == L'\\' )
  2299. {
  2300. *slashCount += 1;
  2301. }
  2302. }
  2303. }
  2304. STATIC
  2305. LPWSTR
  2306. NwpGetUncObjectName(
  2307. IN LPWSTR ContainerName
  2308. )
  2309. {
  2310. WORD length = 2;
  2311. WORD totalLength = (WORD) wcslen( ContainerName );
  2312. if ( totalLength < 2 )
  2313. return 0;
  2314. while ( length < totalLength )
  2315. {
  2316. if ( ContainerName[length] == L'.' )
  2317. ContainerName[length] = L'\0';
  2318. length++;
  2319. }
  2320. length = 2;
  2321. while ( length < totalLength && ContainerName[length] != L'\\' )
  2322. {
  2323. length++;
  2324. }
  2325. if ( ( ContainerName[length + 1] == L'C' ||
  2326. ContainerName[length + 1] == L'c' ) &&
  2327. ( ContainerName[length + 2] == L'N' ||
  2328. ContainerName[length + 2] == L'n' ) &&
  2329. ContainerName[length + 3] == L'=' )
  2330. {
  2331. ContainerName[length + 2] = L'\\';
  2332. ContainerName[length + 3] = L'\\';
  2333. return (ContainerName + length + 2);
  2334. }
  2335. ContainerName[length - 1] = L'\\';
  2336. return (ContainerName + length - 1);
  2337. }
  2338. STATIC
  2339. WORD
  2340. NwpGetSlashCount(
  2341. IN LPWSTR lpstrUnc
  2342. )
  2343. {
  2344. WORD count = 0;
  2345. WORD i;
  2346. WORD length = (WORD) wcslen( lpstrUnc );
  2347. for ( i = 0; i < length; i++ )
  2348. {
  2349. if ( lpstrUnc[i] == L'\\' )
  2350. {
  2351. count++;
  2352. }
  2353. }
  2354. return count;
  2355. }
  2356. DWORD
  2357. NwpMapRpcError(
  2358. IN DWORD RpcError
  2359. )
  2360. /*++
  2361. Routine Description:
  2362. This routine maps the RPC error into a more meaningful windows
  2363. error for the caller.
  2364. Arguments:
  2365. RpcError - Supplies the exception error raised by RPC
  2366. Return Value:
  2367. Returns the mapped error.
  2368. --*/
  2369. {
  2370. switch (RpcError) {
  2371. case RPC_S_UNKNOWN_IF:
  2372. case RPC_S_SERVER_UNAVAILABLE:
  2373. return WN_NO_NETWORK;
  2374. case RPC_S_INVALID_BINDING:
  2375. case RPC_X_SS_IN_NULL_CONTEXT:
  2376. case RPC_X_SS_CONTEXT_DAMAGED:
  2377. case RPC_X_SS_HANDLES_MISMATCH:
  2378. case ERROR_INVALID_HANDLE:
  2379. return ERROR_INVALID_HANDLE;
  2380. case RPC_X_NULL_REF_POINTER:
  2381. return ERROR_INVALID_PARAMETER;
  2382. case EXCEPTION_ACCESS_VIOLATION:
  2383. return ERROR_INVALID_ADDRESS;
  2384. default:
  2385. return RpcError;
  2386. }
  2387. }