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.

1464 lines
36 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. gateway.c
  5. Abstract:
  6. This module contains gateway devices routines supported by
  7. NetWare Workstation service.
  8. Author:
  9. Chuck Y Chan (ChuckC) 31-Oct-1993
  10. Revision History:
  11. --*/
  12. #include <nw.h>
  13. #include <handle.h>
  14. #include <nwreg.h>
  15. #include <nwlsa.h>
  16. #include <nwapi.h>
  17. #include <lmcons.h>
  18. #include <lmshare.h>
  19. #include <winsta.h>
  20. #include <winbasep.h> //DosPathToSessionPath
  21. extern BOOL NwLUIDDeviceMapsEnabled;
  22. //
  23. //-------------------------------------------------------------------//
  24. // //
  25. // External Function Prototypes //
  26. // //
  27. //-------------------------------------------------------------------//
  28. //
  29. // GetProcAddress typedef for winsta.dll function WinStationEnumerateW
  30. //
  31. typedef BOOLEAN (*PWINSTATION_ENUMERATE) (
  32. HANDLE hServer,
  33. PSESSIONIDW *ppLogonId,
  34. PULONG pEntries
  35. );
  36. //
  37. // GetProcAddress typedef for winsta.dll function WinStationFreeMemory
  38. //
  39. typedef BOOLEAN (*PWINSTATION_FREE_MEMORY) ( PVOID);
  40. LPTSTR
  41. NwReturnSessionPath(
  42. IN LPTSTR LocalDeviceName
  43. );
  44. //-------------------------------------------------------------------//
  45. // //
  46. // Local Function Prototypes //
  47. // //
  48. //-------------------------------------------------------------------//
  49. DWORD
  50. NwPopulateGWDosDevice(
  51. LPWSTR DeviceName,
  52. LPWSTR GetwayPath
  53. );
  54. //
  55. // wrapper round the RPC routines.
  56. //
  57. DWORD
  58. NwrEnumGWDevices(
  59. LPWSTR Reserved,
  60. PDWORD Index,
  61. LPBYTE Buffer,
  62. DWORD BufferSize,
  63. LPDWORD BytesNeeded,
  64. LPDWORD EntriesRead
  65. )
  66. /*++
  67. Routine Description:
  68. This routine enumerates the special gateway devices (redirections)
  69. that are cureently in use.
  70. Arguments:
  71. Index - Point to start enumeration. Should be zero for first call.
  72. This is set by the function and can be used to resume the
  73. enumeration.
  74. Buffer - buffer for return data
  75. BufferSize - size of buffer in bytes
  76. BytesNeeded - number of bytes needed to return all the data
  77. EntriesRead - number of entries read
  78. Return Value:
  79. Returns the appropriate Win32 error. If NO_ERROR or ERROR_MORE_DATA
  80. then EntriesRead will indicated the number of valid entries in buffer.
  81. --*/
  82. {
  83. UNREFERENCED_PARAMETER(Reserved);
  84. return ( NwEnumerateGWDevices(
  85. Index,
  86. Buffer,
  87. BufferSize,
  88. BytesNeeded,
  89. EntriesRead
  90. ) ) ;
  91. }
  92. DWORD
  93. NwrAddGWDevice(
  94. LPWSTR Reserved,
  95. LPWSTR DeviceName,
  96. LPWSTR RemoteName,
  97. LPWSTR AccountName,
  98. LPWSTR Password,
  99. DWORD Flags
  100. )
  101. /*++
  102. Routine Description:
  103. This routine adds a gateway redirection.
  104. Arguments:
  105. DeviceName - the drive to redirect
  106. RemoteName - the remote network resource to redirect to
  107. Flags - supplies the options (eg. UpdateRegistry & make this sticky)
  108. Return Value:
  109. Returns the appropriate Win32 error.
  110. --*/
  111. {
  112. DWORD status ;
  113. UNREFERENCED_PARAMETER(Reserved);
  114. //
  115. // make connection to the server to ensure we have a connection.
  116. // if GatewayConnectionAlways is false, the function will immediately
  117. // delete the connection, so this will just be an access check.
  118. //
  119. status = NwCreateGWConnection( RemoteName,
  120. AccountName,
  121. Password,
  122. GatewayConnectionAlways) ;
  123. if (status != NO_ERROR)
  124. {
  125. return status ;
  126. }
  127. //
  128. // make the symbolic link
  129. //
  130. return ( NwCreateGWDevice(
  131. DeviceName,
  132. RemoteName,
  133. Flags
  134. ) ) ;
  135. }
  136. DWORD
  137. NwrDeleteGWDevice(
  138. LPWSTR Reserved,
  139. LPWSTR DeviceName,
  140. DWORD Flags
  141. )
  142. /*++
  143. Routine Description:
  144. This routine enumerates the special gateway devices (redirections)
  145. that are cureently in use.
  146. Arguments:
  147. Index - Point to start enumeration. Should be zero for first call.
  148. This is set by the function and can be used to resume the
  149. enumeration.
  150. Buffer - buffer for return data
  151. BufferSize - size of buffer in bytes
  152. BytesNeeded - number of bytes needed to return all the data
  153. EntriesRead - number of entries read
  154. Return Value:
  155. Returns the appropriate Win32 error.
  156. --*/
  157. {
  158. UNREFERENCED_PARAMETER(Reserved);
  159. return ( NwRemoveGWDevice(
  160. DeviceName,
  161. Flags
  162. ) ) ;
  163. }
  164. DWORD
  165. NwrQueryGatewayAccount(
  166. LPWSTR Reserved,
  167. LPWSTR AccountName,
  168. DWORD AccountNameLen,
  169. LPDWORD AccountCharsNeeded,
  170. LPWSTR Password,
  171. DWORD PasswordLen,
  172. LPDWORD PasswordCharsNeeded
  173. )
  174. /*++
  175. Routine Description:
  176. Query the gateway account info. specifically, the Account name and
  177. the passeord stored as an LSA secret.
  178. Arguments:
  179. AccountName - buffer used to return account name
  180. AccountNameLen - length of buffer
  181. AccountCharsNeeded - number of chars needed. only set properly if
  182. AccountNameLen is too small.
  183. Password - buffer used to return account name
  184. PasswordLen - length of buffer
  185. PasswordCharsNeeded - number of chars needed, only set properly if
  186. PasswordLen is too small.
  187. Return Value:
  188. Returns the appropriate Win32 error.
  189. --*/
  190. {
  191. UNREFERENCED_PARAMETER(Reserved);
  192. return ( NwQueryGWAccount(
  193. AccountName,
  194. AccountNameLen,
  195. AccountCharsNeeded,
  196. Password,
  197. PasswordLen,
  198. PasswordCharsNeeded
  199. ) ) ;
  200. }
  201. DWORD
  202. NwrSetGatewayAccount(
  203. LPWSTR Reserved,
  204. LPWSTR AccountName,
  205. LPWSTR Password
  206. )
  207. /*++
  208. Routine Description:
  209. Set the account and password to be used for gateway access.
  210. Arguments:
  211. AccountName - the account (NULL terminated)
  212. Password - the password string (NULL terminated)
  213. Return Value:
  214. Returns the appropriate Win32 error.
  215. --*/
  216. {
  217. UNREFERENCED_PARAMETER(Reserved);
  218. return ( NwSetGWAccount(
  219. AccountName,
  220. Password
  221. ) ) ;
  222. }
  223. //
  224. // actual functions
  225. //
  226. DWORD
  227. NwEnumerateGWDevices(
  228. LPDWORD Index,
  229. LPBYTE Buffer,
  230. DWORD BufferSize,
  231. LPDWORD BytesNeeded,
  232. LPDWORD EntriesRead
  233. )
  234. /*++
  235. Routine Description:
  236. This routine enumerates the special gateway devices (redirections)
  237. that are cureently in use.
  238. Arguments:
  239. Index - Point to start enumeration. Should be zero for first call.
  240. This is set by the function and can be used to resume the
  241. enumeration.
  242. Buffer - buffer for return data
  243. BufferSize - size of buffer in bytes
  244. BytesNeeded - number of bytes needed to return all the data
  245. EntriesRead - number of entries read
  246. Return Value:
  247. Returns the appropriate Win32 error.
  248. --*/
  249. {
  250. DWORD NwRdrNameLength, NwProviderNameSize ;
  251. DWORD i, status ;
  252. DWORD Length, Count, BytesRequired, SkipCount ;
  253. WCHAR Drive[3] ;
  254. WCHAR Path[MAX_PATH+1] ;
  255. NETRESOURCEW *lpNetRes = NULL ;
  256. LPBYTE BufferEnd = NULL ;
  257. if (!Buffer)
  258. {
  259. return ERROR_INVALID_PARAMETER;
  260. }
  261. lpNetRes = (NETRESOURCEW *) Buffer;
  262. BufferEnd = Buffer + ROUND_DOWN_COUNT(BufferSize,ALIGN_WCHAR);
  263. //
  264. // init the parts of the drives string we never change
  265. //
  266. Drive[1] = L':' ;
  267. Drive[2] = 0 ;
  268. Count = 0 ;
  269. BytesRequired = 0 ;
  270. SkipCount = *Index ;
  271. NwProviderNameSize = wcslen(NwProviderName) + 1 ;
  272. NwRdrNameLength = sizeof(DD_NWFS_DEVICE_NAME_U)/sizeof(WCHAR) - 1 ;
  273. //
  274. // for all logical drives
  275. //
  276. for (i = 0; i <26 ; i++)
  277. {
  278. BOOL GatewayDrive = FALSE ;
  279. Drive[0] = L'A' + (USHORT)i ;
  280. //
  281. // get the symbolic link
  282. //
  283. Length = QueryDosDeviceW(Drive,
  284. Path,
  285. sizeof(Path)/sizeof(Path[0])) ;
  286. //
  287. // the value must be at least as long as our device name
  288. //
  289. if (Length >= NwRdrNameLength + 4)
  290. {
  291. //
  292. // and it must match the following criteria:
  293. // 1) start with \device\nwrdr
  294. // 2) must have '\' after \device\nwrdr
  295. // 3) must not have colon (ie. must be`
  296. // \\device\nwrdr\server\share, and not
  297. // \\device\nwrdr\x:\server\share
  298. //
  299. if ((_wcsnicmp(Path,DD_NWFS_DEVICE_NAME_U,NwRdrNameLength)
  300. == 0)
  301. && (Path[NwRdrNameLength] == '\\')
  302. && (Path[NwRdrNameLength+2] != ':'))
  303. {
  304. //
  305. // if this is an indexed read, skip the first N.
  306. // this is inefficient, but we do not expect to
  307. // have to go thru this very often. there are few
  308. // such devices, and any reasonable buffer (even 1K)
  309. // should get them all first time.
  310. //
  311. if (SkipCount)
  312. SkipCount-- ;
  313. else
  314. GatewayDrive = TRUE ; // found a drive we want
  315. }
  316. }
  317. if (GatewayDrive)
  318. {
  319. //
  320. // we meet all criteria above
  321. //
  322. DWORD UncSize ;
  323. UncSize = Length - NwRdrNameLength + 2 ;
  324. BytesRequired += ( sizeof(NETRESOURCE) +
  325. (UncSize * sizeof(WCHAR)) +
  326. (NwProviderNameSize * sizeof(WCHAR)) +
  327. (3 * sizeof(WCHAR))) ; // 3 for drive, X:\0
  328. if (BytesRequired <= BufferSize)
  329. {
  330. LPWSTR lpStr = (LPWSTR) BufferEnd ;
  331. Count++ ;
  332. //
  333. // copy the drive name
  334. //
  335. lpStr -= 3 ;
  336. wcscpy(lpStr, Drive) ;
  337. lpNetRes->lpLocalName = (LPWSTR) ((LPBYTE)lpStr - Buffer) ;
  338. //
  339. // copy the UNC name
  340. //
  341. lpStr -= UncSize ; // for the UNC name
  342. lpStr[0] = L'\\' ;
  343. wcscpy(lpStr+1, Path+NwRdrNameLength) ;
  344. lpNetRes->lpRemoteName = (LPWSTR) ((LPBYTE)lpStr - Buffer) ;
  345. //
  346. // copy the provider name
  347. //
  348. lpStr -= NwProviderNameSize ; // for the provider name
  349. wcscpy(lpStr, NwProviderName) ;
  350. lpNetRes->lpProvider = (LPWSTR) ((LPBYTE)lpStr - Buffer) ;
  351. //
  352. // set up the rest of the structure
  353. //
  354. lpNetRes->dwScope = RESOURCE_CONNECTED ;
  355. lpNetRes->dwType = RESOURCETYPE_DISK ;
  356. lpNetRes->dwDisplayType = 0 ;
  357. lpNetRes->dwUsage = 0 ;
  358. lpNetRes->lpComment = 0 ;
  359. lpNetRes++ ;
  360. BufferEnd = (LPBYTE) lpStr ;
  361. }
  362. }
  363. }
  364. *EntriesRead = Count ; // set number of entries
  365. *Index += Count ; // move index
  366. *BytesNeeded = BytesRequired ; // set bytes needed
  367. if (BytesRequired == 0) // no info left
  368. return (ERROR_NO_MORE_ITEMS) ;
  369. if (BytesRequired > BufferSize)
  370. {
  371. return (ERROR_MORE_DATA) ;
  372. }
  373. return NO_ERROR ;
  374. }
  375. DWORD
  376. NwCreateGWDevice(
  377. LPWSTR DeviceName,
  378. LPWSTR RemoteName,
  379. DWORD Flags
  380. )
  381. /*++
  382. Routine Description:
  383. This routine adds a gateway redirection.
  384. Arguments:
  385. DeviceName - the drive to redirect
  386. RemoteName - the remote network resource to redirect to
  387. Flags - supplies the options (eg. UpdateRegistry & make this sticky)
  388. Return Value:
  389. Returns the appropriate Win32 error.
  390. --*/
  391. {
  392. LPWSTR ConnectName = NULL;
  393. DWORD status ;
  394. WCHAR Path [MAX_PATH + 1] ;
  395. //
  396. // validate/canon the name. Use a drive to specific we allow UNC only.
  397. //
  398. if ((status = NwLibCanonRemoteName( L"A:",
  399. RemoteName,
  400. &ConnectName,
  401. NULL
  402. )) != NO_ERROR)
  403. {
  404. return status;
  405. }
  406. //
  407. // build up the full name of \device\nwrdr\server\volume
  408. //
  409. wcscpy(Path, DD_NWFS_DEVICE_NAME_U) ;
  410. wcscat(Path, ConnectName+1 ) ;
  411. //
  412. // create the symbolic link, Gateway specific, since there is no true user contacts
  413. //
  414. status = NwCreateSymbolicLink(DeviceName, Path, TRUE, FALSE) ;
  415. (void) LocalFree((HLOCAL) ConnectName);
  416. //
  417. // if update registry is set, write it out
  418. //
  419. if ((status == NO_ERROR) && (Flags & NW_GW_UPDATE_REGISTRY))
  420. {
  421. HKEY hKey ;
  422. DWORD dwDisposition ;
  423. //
  424. //
  425. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  426. // \NWCWorkstation\Drives (create it if not there)
  427. //
  428. status = RegCreateKeyExW(
  429. HKEY_LOCAL_MACHINE,
  430. NW_WORKSTATION_GATEWAY_DRIVES,
  431. 0,
  432. L"",
  433. REG_OPTION_NON_VOLATILE,
  434. KEY_WRITE, // desired access
  435. NULL, // default security
  436. &hKey,
  437. &dwDisposition // ignored
  438. );
  439. if ( status )
  440. return status ;
  441. status = RegSetValueExW(
  442. hKey,
  443. DeviceName,
  444. 0,
  445. REG_SZ,
  446. (LPBYTE) RemoteName,
  447. (wcslen(RemoteName)+1) * sizeof(WCHAR)) ;
  448. RegCloseKey( hKey );
  449. if (status == ERROR_SUCCESS && IsTerminalServer() &&
  450. (NwLUIDDeviceMapsEnabled == FALSE)) {
  451. status = NwPopulateGWDosDevice(DeviceName, Path) ;
  452. }
  453. }
  454. return status ;
  455. }
  456. DWORD
  457. NwRemoveGWDevice(
  458. LPWSTR DeviceName,
  459. DWORD Flags
  460. )
  461. /*++
  462. Routine Description:
  463. This routine deletes a gateway redirection.
  464. Arguments:
  465. DeviceName - the drive to delete
  466. Flags - supplies the options (eg. UpdateRegistry & make this sticky)
  467. Return Value:
  468. Returns the appropriate Win32 error.
  469. --*/
  470. {
  471. DWORD status ;
  472. LPWSTR Local = NULL ;
  473. //LPWSTR SessionDeviceName;
  474. if (status = NwLibCanonLocalName(DeviceName,
  475. &Local,
  476. NULL))
  477. return status ;
  478. //SessionDeviceName = NwReturnSessionPath(Local);
  479. //if ( SessionDeviceName == NULL ) {
  480. // return ERROR_NOT_ENOUGH_MEMORY;
  481. //}
  482. //
  483. // delete the symbolic link
  484. //
  485. if (! DefineDosDeviceW(DDD_REMOVE_DEFINITION | DDD_RAW_TARGET_PATH,
  486. Local,
  487. //SessionDeviceName,
  488. DD_NWFS_DEVICE_NAME_U))
  489. {
  490. status = ERROR_INVALID_DRIVE ;
  491. }
  492. //if ( SessionDeviceName ) {
  493. // LocalFree( SessionDeviceName );
  494. //}
  495. //
  496. // If cleanup deleted (dangling) share is set go do it now.
  497. // We loop thru all the shares looking for one that matches that drive.
  498. // Then we ask the server to nuke that dangling share.
  499. //
  500. if ((status == NO_ERROR) && (Flags & NW_GW_CLEANUP_DELETED))
  501. {
  502. HKEY hKey ;
  503. DWORD err ;
  504. //
  505. //
  506. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  507. // \NWCWorkstation\Shares
  508. //
  509. err = RegOpenKeyExW(
  510. HKEY_LOCAL_MACHINE,
  511. NW_WORKSTATION_GATEWAY_SHARES,
  512. REG_OPTION_NON_VOLATILE, // options
  513. KEY_READ | KEY_WRITE, // desired access
  514. &hKey
  515. );
  516. if (err == NO_ERROR)
  517. {
  518. WCHAR Path[MAX_PATH + 1], ShareName[MAX_PATH+1] ;
  519. DWORD dwType, i = 0, dwPathSize, dwShareNameSize ;
  520. do {
  521. dwPathSize = sizeof(Path),
  522. dwShareNameSize = sizeof(ShareName)/sizeof(ShareName[0]) ;
  523. dwType = REG_SZ ;
  524. err = RegEnumValueW(hKey,
  525. i,
  526. ShareName,
  527. &dwShareNameSize,
  528. NULL,
  529. &dwType,
  530. (LPBYTE)Path,
  531. &dwPathSize) ;
  532. //
  533. // Look for matching drive, eg. "X:"
  534. // If have match, cleanup as best we can and break out now.
  535. //
  536. if ((err == NO_ERROR) &&
  537. (_wcsnicmp(Path,DeviceName,2) == 0))
  538. {
  539. (void) NetShareDelSticky( NULL,
  540. ShareName,
  541. 0 ) ;
  542. (void) RegDeleteValueW(hKey,
  543. ShareName) ;
  544. break ;
  545. }
  546. i++ ;
  547. } while (err == NO_ERROR) ;
  548. RegCloseKey( hKey );
  549. }
  550. }
  551. //
  552. // if update registry is set, write it out
  553. //
  554. if ((status == NO_ERROR) && (Flags & NW_GW_UPDATE_REGISTRY))
  555. {
  556. HKEY hKey ;
  557. WCHAR Path[MAX_PATH + 1] ;
  558. DWORD dwType, dwSize = sizeof(Path) ;
  559. //
  560. //
  561. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  562. // \NWCWorkstation\Drives
  563. //
  564. status = RegOpenKeyExW(
  565. HKEY_LOCAL_MACHINE,
  566. NW_WORKSTATION_GATEWAY_DRIVES,
  567. REG_OPTION_NON_VOLATILE, // options
  568. KEY_READ | KEY_WRITE, // desired access
  569. &hKey
  570. );
  571. if ( status )
  572. goto ExitPoint ;
  573. if (GatewayConnectionAlways)
  574. {
  575. //
  576. // Read the remote path and delete the connection
  577. // if we made one in the first place.
  578. //
  579. status = RegQueryValueExW(
  580. hKey,
  581. Local,
  582. NULL,
  583. &dwType,
  584. (LPBYTE) Path,
  585. &dwSize
  586. );
  587. if (status == NO_ERROR)
  588. {
  589. (void) NwDeleteGWConnection(Path) ;
  590. }
  591. }
  592. status = RegDeleteValueW(
  593. hKey,
  594. DeviceName
  595. ) ;
  596. RegCloseKey( hKey );
  597. }
  598. ExitPoint:
  599. if (Local)
  600. (void) LocalFree((HLOCAL)Local) ;
  601. return status ;
  602. }
  603. DWORD
  604. NwGetGatewayResource(
  605. IN LPWSTR LocalName,
  606. OUT LPWSTR RemoteName,
  607. IN DWORD RemoteNameLen,
  608. OUT LPDWORD CharsRequired
  609. )
  610. /*++
  611. Routine Description:
  612. For a gateway devicename, get the network resource associated with it.
  613. Arguments:
  614. LocalName - name of devive to query
  615. RemoteName - buffer to return the network resource
  616. RemoteNameLen - size of buffer (chars)
  617. CharsRequired - the number of chars needed
  618. Return Value:
  619. WN_SUCCESS - success (the device is a gateway redirection)
  620. WN_MORE_DATA - buffer too small, but device is a gateway redirection
  621. WN_NOT_CONNECTED - not a gateway redirection
  622. --*/
  623. {
  624. WCHAR Path[MAX_PATH+1] ;
  625. DWORD Length ;
  626. DWORD NwRdrNameLength ;
  627. NwRdrNameLength = sizeof(DD_NWFS_DEVICE_NAME_U)/sizeof(WCHAR) - 1 ;
  628. //
  629. // retrieve symbolic link for the device
  630. //
  631. Length = QueryDosDeviceW(LocalName,
  632. Path,
  633. sizeof(Path)/sizeof(Path[0])) ;
  634. //
  635. // the result is only interesting if it can at least fit:
  636. // \device\nwrdr\x\y
  637. //
  638. if (Length >= NwRdrNameLength + 4)
  639. {
  640. //
  641. // check to make sure that the prefix is coreect, and that
  642. // it is not of form: \device\nwrdr\x:\...
  643. //
  644. if ((_wcsnicmp(Path,DD_NWFS_DEVICE_NAME_U,NwRdrNameLength) == 0)
  645. && (Path[NwRdrNameLength] == '\\')
  646. && (Path[NwRdrNameLength+2] != ':'))
  647. {
  648. //
  649. // check buffer size
  650. //
  651. if (RemoteNameLen < ((Length - NwRdrNameLength) + 1))
  652. {
  653. if (CharsRequired)
  654. *CharsRequired = ((Length - NwRdrNameLength) + 1) ;
  655. return WN_MORE_DATA ;
  656. }
  657. *RemoteName = L'\\' ;
  658. wcscpy(RemoteName+1,Path+NwRdrNameLength) ;
  659. return WN_SUCCESS ;
  660. }
  661. }
  662. return WN_NOT_CONNECTED ;
  663. }
  664. DWORD
  665. NwQueryGWAccount(
  666. LPWSTR AccountName,
  667. DWORD AccountNameLen,
  668. LPDWORD AccountCharsNeeded,
  669. LPWSTR Password,
  670. DWORD PasswordLen,
  671. LPDWORD PasswordCharsNeeded
  672. )
  673. /*++
  674. Routine Description:
  675. Query the gateway account info. specifically, the Account name and
  676. the passeord stored as an LSA secret.
  677. Arguments:
  678. AccountName - buffer used to return account name
  679. AccountNameLen - length of buffer
  680. AccountCharsNeeded - number of chars needed. only set properly if
  681. AccountNameLen is too small.
  682. Password - buffer used to return account name
  683. PasswordLen - length of buffer
  684. PasswordCharsNeeded - number of chars needed, only set properly if
  685. PasswordLen is too small.
  686. Return Value:
  687. Returns the appropriate Win32 error.
  688. --*/
  689. {
  690. DWORD status = NO_ERROR ;
  691. LONG RegError;
  692. HKEY WkstaKey = NULL;
  693. LPWSTR GatewayAccount = NULL;
  694. PUNICODE_STRING StoredPassword = NULL;
  695. PUNICODE_STRING StoredOldPassword = NULL;
  696. if ( !AccountName || !Password )
  697. {
  698. return ERROR_INVALID_PARAMETER;
  699. }
  700. *AccountCharsNeeded = 0 ;
  701. *PasswordCharsNeeded = 0 ;
  702. //
  703. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  704. // \NWCWorkstation\Parameters
  705. //
  706. RegError = RegOpenKeyExW(
  707. HKEY_LOCAL_MACHINE,
  708. NW_WORKSTATION_REGKEY,
  709. REG_OPTION_NON_VOLATILE, // options
  710. KEY_READ, // desired access
  711. &WkstaKey
  712. );
  713. if (RegError != ERROR_SUCCESS)
  714. {
  715. return (RegError);
  716. }
  717. //
  718. // Read the gateway account from the registry.
  719. //
  720. status = NwReadRegValue(
  721. WkstaKey,
  722. NW_GATEWAYACCOUNT_VALUENAME,
  723. &GatewayAccount
  724. );
  725. if (status != NO_ERROR)
  726. {
  727. if (status != ERROR_FILE_NOT_FOUND)
  728. goto CleanExit;
  729. if (AccountNameLen > 0)
  730. *AccountName = 0 ;
  731. status = NO_ERROR ;
  732. }
  733. else
  734. {
  735. *AccountCharsNeeded = wcslen(GatewayAccount) + 1 ;
  736. if (*AccountCharsNeeded > AccountNameLen)
  737. {
  738. status = ERROR_INSUFFICIENT_BUFFER ;
  739. goto CleanExit;
  740. }
  741. wcscpy(AccountName,GatewayAccount);
  742. }
  743. //
  744. // Read the password from its secret object in LSA.
  745. //
  746. status = NwGetPassword(
  747. GATEWAY_USER,
  748. &StoredPassword, // Must be freed with LsaFreeMemory
  749. &StoredOldPassword // Must be freed with LsaFreeMemory
  750. );
  751. if (status != NO_ERROR)
  752. {
  753. if (status != ERROR_FILE_NOT_FOUND)
  754. goto CleanExit;
  755. if (PasswordLen > 0)
  756. *Password = 0 ;
  757. status = NO_ERROR ;
  758. }
  759. else
  760. {
  761. *PasswordCharsNeeded = StoredPassword->Length/sizeof(WCHAR) + 1 ;
  762. if ((StoredPassword->Length/sizeof(WCHAR)) >= PasswordLen)
  763. {
  764. status = ERROR_INSUFFICIENT_BUFFER ;
  765. goto CleanExit;
  766. }
  767. wcsncpy(Password,
  768. StoredPassword->Buffer,
  769. StoredPassword->Length/sizeof(WCHAR));
  770. Password[StoredPassword->Length/sizeof(WCHAR)] = 0 ;
  771. }
  772. CleanExit:
  773. if (StoredPassword != NULL) {
  774. (void) LsaFreeMemory((PVOID) StoredPassword);
  775. }
  776. if (StoredOldPassword != NULL) {
  777. (void) LsaFreeMemory((PVOID) StoredOldPassword);
  778. }
  779. if (GatewayAccount != NULL) {
  780. (void) LocalFree((HLOCAL) GatewayAccount);
  781. }
  782. (void) RegCloseKey(WkstaKey);
  783. return status ;
  784. }
  785. DWORD
  786. NwSetGWAccount(
  787. LPWSTR AccountName,
  788. LPWSTR Password
  789. )
  790. /*++
  791. Routine Description:
  792. Set the account and password to be used for gateway access.
  793. Arguments:
  794. AccountName - the account (NULL terminated)
  795. Password - the password string (NULL terminated)
  796. Return Value:
  797. Returns the appropriate Win32 error.
  798. --*/
  799. {
  800. DWORD status ;
  801. HKEY WkstaKey = NULL;
  802. //
  803. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  804. // \NWCWorkstation\Parameters
  805. //
  806. status = RegOpenKeyExW(
  807. HKEY_LOCAL_MACHINE,
  808. NW_WORKSTATION_REGKEY,
  809. REG_OPTION_NON_VOLATILE, // options
  810. KEY_WRITE, // desired access
  811. &WkstaKey
  812. );
  813. if (status != ERROR_SUCCESS)
  814. {
  815. return (status);
  816. }
  817. //
  818. // Write the account name out
  819. //
  820. status = RegSetValueExW(
  821. WkstaKey,
  822. NW_GATEWAYACCOUNT_VALUENAME,
  823. 0,
  824. REG_SZ,
  825. (LPVOID) AccountName,
  826. (wcslen(AccountName) + 1) * sizeof(WCHAR)
  827. );
  828. if (status == NO_ERROR)
  829. {
  830. status = NwSetPassword(
  831. GATEWAY_USER,
  832. Password) ;
  833. }
  834. return status ;
  835. }
  836. DWORD
  837. NwCreateRedirections(
  838. LPWSTR Account,
  839. LPWSTR Password
  840. )
  841. /*++
  842. Routine Description:
  843. Create the gateway redirections from what is stored in registry.
  844. As we go along, we validate that we have access to it using the
  845. gateway account.
  846. Arguments:
  847. AccountName - the account (NULL terminated)
  848. Password - the password string (NULL terminated)
  849. Return Value:
  850. Returns the appropriate Win32 error.
  851. --*/
  852. {
  853. DWORD err, i, type ;
  854. HKEY hKey ;
  855. FILETIME FileTime ;
  856. WCHAR Class[256], Device[64], Path[MAX_PATH+1] ;
  857. DWORD dwClass, dwSubKeys, dwMaxSubKey, dwMaxClass,
  858. dwValues, dwMaxValueName, dwMaxValueData, dwSDLength,
  859. dwDeviceLength, dwPathLength ;
  860. //
  861. //
  862. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  863. // \NWCGateway\Parameters
  864. //
  865. err = RegOpenKeyExW(
  866. HKEY_LOCAL_MACHINE,
  867. NW_WORKSTATION_GATEWAY_DRIVES,
  868. REG_OPTION_NON_VOLATILE, // options
  869. KEY_READ, // desired access
  870. &hKey
  871. );
  872. if ( err )
  873. return err ;
  874. dwClass = sizeof(Class)/sizeof(Class[0]) ;
  875. err = RegQueryInfoKeyW(hKey,
  876. Class,
  877. &dwClass,
  878. NULL,
  879. &dwSubKeys,
  880. &dwMaxSubKey,
  881. &dwMaxClass,
  882. &dwValues,
  883. &dwMaxValueName,
  884. &dwMaxValueData,
  885. &dwSDLength,
  886. &FileTime) ;
  887. if ( err )
  888. {
  889. RegCloseKey( hKey );
  890. return err ;
  891. }
  892. //
  893. // for each value we have a redirection to recreate
  894. //
  895. for (i = 0; i < dwValues; i++)
  896. {
  897. dwDeviceLength = sizeof(Device)/sizeof(Device[0]) ;
  898. dwPathLength = sizeof(Path) ;
  899. type = REG_SZ ;
  900. err = RegEnumValueW(hKey,
  901. i,
  902. Device,
  903. &dwDeviceLength,
  904. NULL,
  905. &type,
  906. (LPBYTE)Path,
  907. &dwPathLength) ;
  908. //
  909. // connect to the server. this will take up a connection but
  910. // it will also make sure we have one. on a low limit server, if
  911. // we rely on UNC then it is quite likely that other people will
  912. // come along & use up all the connections, preventing the Gateway
  913. // from getting to it.
  914. //
  915. // user may turn this off by setting Registry value that results
  916. // GatewayConnectionAlways being false.
  917. //
  918. // regardless of result, we carry on. so if server is down & comes
  919. // up later, the symbolic link to UNC will still work.
  920. //
  921. if (!err)
  922. {
  923. (void) NwCreateGWConnection( Path,
  924. Account,
  925. Password,
  926. GatewayConnectionAlways) ;
  927. }
  928. //
  929. // create the symbolic link
  930. //
  931. if (!err)
  932. {
  933. err = NwCreateGWDevice(Device, Path, 0L) ;
  934. }
  935. if (err)
  936. {
  937. //
  938. // log the error in the event log
  939. //
  940. WCHAR Number[16] ;
  941. LPWSTR InsertStrings[3] ;
  942. wsprintfW(Number, L"%d", err) ;
  943. InsertStrings[0] = Device ;
  944. InsertStrings[1] = Path ;
  945. InsertStrings[2] = Number ;
  946. NwLogEvent(EVENT_NWWKSTA_CANNOT_REDIRECT_DEVICES,
  947. 3,
  948. InsertStrings,
  949. 0) ;
  950. }
  951. }
  952. RegCloseKey( hKey );
  953. return NO_ERROR ;
  954. }
  955. DWORD
  956. NwDeleteRedirections(
  957. VOID
  958. )
  959. /*++
  960. Routine Description:
  961. Delete all gateway devices
  962. Arguments:
  963. Return Value:
  964. Returns the appropriate Win32 error.
  965. --*/
  966. {
  967. LPBYTE Buffer ;
  968. DWORD i, status, Index, BufferSize, EntriesRead, BytesNeeded ;
  969. LPNETRESOURCE lpNetRes ;
  970. Index = 0 ;
  971. //
  972. // below is good initial guess
  973. //
  974. BufferSize = 26 * (sizeof(NETRESOURCE) +
  975. (3 + MAX_PATH + 1 + MAX_PATH + 1) * sizeof(WCHAR)) ;
  976. Buffer = (LPBYTE) LocalAlloc(LPTR, BufferSize) ;
  977. if (!Buffer)
  978. return (GetLastError()) ;
  979. lpNetRes = (LPNETRESOURCE) Buffer ;
  980. status = NwrEnumGWDevices(NULL,
  981. &Index,
  982. Buffer,
  983. BufferSize,
  984. &BytesNeeded,
  985. &EntriesRead) ;
  986. //
  987. // reallocate as need
  988. //
  989. if (status == ERROR_MORE_DATA || status == ERROR_INSUFFICIENT_BUFFER)
  990. {
  991. Buffer = (LPBYTE) LocalReAlloc((HLOCAL)Buffer,
  992. BytesNeeded,
  993. LMEM_ZEROINIT) ;
  994. if (!Buffer)
  995. return (GetLastError()) ;
  996. Index = 0 ;
  997. BufferSize = BytesNeeded ;
  998. status = NwrEnumGWDevices(NULL,
  999. &Index,
  1000. Buffer,
  1001. BufferSize,
  1002. &BytesNeeded,
  1003. &EntriesRead) ;
  1004. }
  1005. if (status != NO_ERROR)
  1006. return status ;
  1007. //
  1008. // loop thru and delete all the devices
  1009. //
  1010. for (i = 0; i < EntriesRead; i++)
  1011. {
  1012. status = NwrDeleteGWDevice(NULL,
  1013. (LPWSTR)((LPBYTE)Buffer +
  1014. (DWORD_PTR)lpNetRes->lpLocalName),
  1015. 0L) ;
  1016. //
  1017. // no need report the error, since we are shutting down.
  1018. // there is no real deletion here - just removing the symbolic link.
  1019. //
  1020. lpNetRes++ ;
  1021. }
  1022. return NO_ERROR ;
  1023. }
  1024. DWORD
  1025. NwPopulateGWDosDevice(
  1026. IN LPWSTR DeviceName,
  1027. IN LPWSTR GatewayPath
  1028. )
  1029. /*++
  1030. Routine Description:
  1031. This routine poplaute the gateway dos device to all the active terminal sessions
  1032. Arguments:
  1033. DeviceName - the drive to redirect
  1034. GatewayPath - the remote network resource of the gateway drive
  1035. Return Value:
  1036. Returns the appropriate Win32 error.
  1037. --*/
  1038. {
  1039. DWORD status = ERROR_SUCCESS;
  1040. HMODULE hwinsta = NULL;
  1041. PWINSTATION_ENUMERATE pfnWinStationEnumerate;
  1042. PWINSTATION_FREE_MEMORY pfnWinStationFreeMemory;
  1043. PSESSIONIDW pSessionIds = NULL;
  1044. ULONG SessionCount;
  1045. ULONG SessionId;
  1046. LPWSTR pSessionPath = NULL;
  1047. /*
  1048. * Dynmaically load the winsta.dll
  1049. */
  1050. if ( (hwinsta = LoadLibraryW( L"WINSTA" )) == NULL ) {
  1051. status = ERROR_DLL_NOT_FOUND;
  1052. goto Exit;
  1053. }
  1054. pfnWinStationEnumerate = (PWINSTATION_ENUMERATE)
  1055. GetProcAddress( hwinsta, "WinStationEnumerateW" );
  1056. pfnWinStationFreeMemory = (PWINSTATION_FREE_MEMORY)
  1057. GetProcAddress( hwinsta, "WinStationFreeMemory" );
  1058. if (!pfnWinStationEnumerate || !pfnWinStationFreeMemory) {
  1059. status = ERROR_INVALID_DLL;
  1060. goto Exit;
  1061. }
  1062. /*
  1063. * Enumerate Sessions
  1064. */
  1065. if ( !pfnWinStationEnumerate( NULL, //Enumerate self
  1066. &pSessionIds,
  1067. &SessionCount ) ) {
  1068. status = GetLastError();
  1069. goto Exit;
  1070. }
  1071. /*
  1072. * Loop through the session, skip the console, ie SessionId = 0
  1073. * Since the gateway device is always created for the console
  1074. */
  1075. for ( SessionId = 1; SessionId < SessionCount; SessionId++ ) {
  1076. if (
  1077. (pSessionIds[SessionId].State != State_Idle) &&
  1078. (pSessionIds[SessionId].State != State_Down) &&
  1079. (pSessionIds[SessionId].State != State_Disconnected)
  1080. ) {
  1081. WCHAR TempBuf[64];
  1082. //
  1083. // Create a Gateway Dos Device for those terminal sessions
  1084. //
  1085. if (!DosPathToSessionPath(
  1086. SessionId,
  1087. DeviceName,
  1088. &pSessionPath
  1089. )) {
  1090. status = GetLastError();
  1091. goto Exit;
  1092. }
  1093. if (!QueryDosDeviceW(
  1094. pSessionPath,
  1095. TempBuf,
  1096. sizeof(TempBuf)
  1097. )) {
  1098. if (GetLastError() != ERROR_FILE_NOT_FOUND) {
  1099. //
  1100. // Most likely failure occurred because our output
  1101. // buffer is too small. It still means someone already
  1102. // has an existing symbolic link for this device for this session.
  1103. // It is ok, just skip this session
  1104. //
  1105. continue;
  1106. }
  1107. // This path is OK
  1108. }
  1109. else {
  1110. //
  1111. // QueryDosDevice successfully an existing symbolic link--
  1112. // somebody is already using this device for this session.
  1113. // Skip this session and continue...
  1114. //
  1115. continue;
  1116. }
  1117. //
  1118. // Create a symbolic link object to the device we are redirecting
  1119. //
  1120. if (! DefineDosDeviceW(
  1121. DDD_RAW_TARGET_PATH | DDD_NO_BROADCAST_SYSTEM,
  1122. pSessionPath,
  1123. GatewayPath
  1124. )) {
  1125. //Cannot create device for this session.
  1126. status = GetLastError();
  1127. goto Exit;
  1128. }
  1129. } //if (pSessionID...
  1130. } //for (SessionID
  1131. Exit:
  1132. if (pSessionIds) {
  1133. pfnWinStationFreeMemory( pSessionIds );
  1134. }
  1135. if (pSessionPath) {
  1136. LocalFree(pSessionPath);
  1137. }
  1138. if (hwinsta) {
  1139. FreeLibrary(hwinsta);
  1140. }
  1141. return status;
  1142. }