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.

1947 lines
53 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. MPRREG.CXX
  5. Abstract:
  6. Contains functions used by MPR to manipulate the registry.
  7. MprOpenKey
  8. MprGetKeyValue
  9. MprEnumKey
  10. MprGetKeyInfo
  11. MprFindDriveInRegistry
  12. I_MprSaveConn
  13. MprSaveDeferFlags
  14. MprSetRegValue
  15. MprCreateRegKey
  16. MprReadConnectionInfo
  17. MprForgetRedirConnection
  18. MprGetRemoteName
  19. QUESTIONS:
  20. 1) Do I need to call RegFlushKey after creating a new key?
  21. Author:
  22. Dan Lafferty (danl) 12-Dec-1991
  23. Environment:
  24. User Mode - Win32
  25. Revision History:
  26. 21-Feb-1997 AnirudhS
  27. Change MprRememberConnection to I_MprSaveConn and MprSaveDeferFlags
  28. for use by setup and by DEFER_UNKNOWN.
  29. 12-Jun-1996 AnirudhS
  30. Got rid of the REMOVE_COLON/RESTORE_COLON scheme for converting
  31. device names to registry key names, since it caused writes to
  32. read-only input parameters.
  33. 08-Mar-1996 AnirudhS
  34. Save the provider type, not the provider name, for persistent
  35. connections. Fix old heap corruption bugs that show up when the
  36. user profile contains incomplete info.
  37. 16-Jun-1995 AnirudhS
  38. Returned DWORDs rather than BOOLs from some functions; changed some
  39. formal parameters from LPWSTR to LPCWSTR.
  40. 24-Nov-1992 Danl
  41. Fixed compiler warnings by always using HKEY rather than HANDLE.
  42. 03-Sept-1992 Danl
  43. MprGetRemoteName: Changed ERROR_BUFFER_OVERFLOW to WN_MORE_DATA.
  44. 12-Dec-1991 danl
  45. Created
  46. --*/
  47. //
  48. // Includes
  49. //
  50. #include "precomp.hxx"
  51. #include <malloc.h> // _alloca
  52. #include <debugfmt.h> // FORMAT_LPTSTR
  53. #include <wincred.h> // CRED_MAX_USERNAME_LENGTH
  54. //
  55. // Macros
  56. //
  57. //
  58. // STACK_ALLOC
  59. //
  60. // Allocates space on the stack for a copy of an input string. The result
  61. // could be NULL if the string is too long to be copied on the stack.
  62. //
  63. #define STACK_ALLOC(str) ((LPWSTR) _alloca((wcslen(str)+1)*sizeof(WCHAR)))
  64. VOID
  65. RemoveColon(
  66. LPWSTR pszCopy,
  67. LPCWSTR pszSource
  68. )
  69. /*++
  70. Routine Description:
  71. This function makes a copy of a string and searches through the copy
  72. for a colon. If a colon is found, it is replaced by a '\0'.
  73. Arguments:
  74. pszCopy - Pointer to the space for the copy.
  75. pszSource - Pointer to the source string.
  76. Return Value:
  77. None.
  78. --*/
  79. {
  80. wcscpy(pszCopy, pszSource);
  81. WCHAR * pColon = wcschr(pszCopy, L':');
  82. if (pColon != NULL)
  83. {
  84. *pColon = L'\0';
  85. }
  86. }
  87. BOOL
  88. MprOpenKey(
  89. IN HKEY hKey,
  90. IN LPTSTR lpSubKey,
  91. OUT PHKEY phKeyHandle,
  92. IN DWORD desiredAccess
  93. )
  94. /*++
  95. Routine Description:
  96. This function opens a handle to a key inside the registry. The major
  97. handle and the path to the subkey are required as input.
  98. Arguments:
  99. hKey - This is one of the well-known root key handles for the portion
  100. of the registry of interest.
  101. lpSubKey - A pointer a string containing the path to the subkey.
  102. phKeyHandle - A pointer to the location where the handle to the subkey
  103. is to be placed.
  104. desiredAccess - Desired Access (Either KEY_READ or KEY_WRITE or both).
  105. Return Value:
  106. TRUE - The operation was successful
  107. FALSE - The operation was not successful.
  108. --*/
  109. {
  110. DWORD status;
  111. REGSAM samDesired = KEY_READ;
  112. HKEY HKCU ;
  113. if(desiredAccess & DA_WRITE) {
  114. samDesired = KEY_READ | KEY_WRITE;
  115. }
  116. else if (desiredAccess & DA_DELETE) {
  117. samDesired = DELETE;
  118. }
  119. HKCU = NULL ;
  120. if ( hKey == HKEY_CURRENT_USER ) {
  121. status = RegOpenCurrentUser(
  122. MAXIMUM_ALLOWED,
  123. &HKCU );
  124. if ( status != 0 )
  125. {
  126. return FALSE ;
  127. }
  128. hKey = HKCU ;
  129. }
  130. status = RegOpenKeyEx(
  131. hKey, // hKey
  132. lpSubKey, // lpSubKey
  133. 0L, // ulOptions (reserved)
  134. samDesired, // desired access security mask
  135. phKeyHandle); // Newly Opened Key Handle
  136. if ( HKCU )
  137. {
  138. RegCloseKey( HKCU );
  139. }
  140. if (status != NO_ERROR) {
  141. MPR_LOG3(ERROR,"MprOpenKey: RegOpenKeyEx(%#lx \"%ws\") failed %d\n",
  142. hKey, lpSubKey, status);
  143. return (FALSE);
  144. }
  145. return(TRUE);
  146. }
  147. BOOL
  148. MprGetKeyValue(
  149. IN HKEY KeyHandle,
  150. IN LPTSTR ValueName,
  151. OUT LPTSTR *ValueString
  152. )
  153. /*++
  154. Routine Description:
  155. This function takes a key handle and a value name, and returns a value
  156. string that is associated with that name.
  157. NOTE: The pointer to the ValueString is allocated by this function.
  158. Arguments:
  159. KeyHandle - This is a handle for the registry key that contains the value.
  160. ValueName - A pointer to a string that identifies the value being
  161. obtained.
  162. ValueString - A pointer to a location that upon exit will contain the
  163. pointer to the returned value.
  164. Return Value:
  165. TRUE - Success
  166. FALSE - A fatal error occured.
  167. --*/
  168. {
  169. DWORD status;
  170. DWORD maxValueLen;
  171. TCHAR Temp[1];
  172. LPTSTR TempValue;
  173. DWORD ValueType;
  174. DWORD NumRequired;
  175. DWORD CharsReturned;
  176. //
  177. // Find the buffer size requirement for the value.
  178. //
  179. status = RegQueryValueEx(
  180. KeyHandle, // hKey
  181. ValueName, // lpValueName
  182. NULL, // lpTitleIndex
  183. &ValueType, // lpType
  184. NULL, // lpData
  185. &maxValueLen); // lpcbData
  186. if (status != NO_ERROR) {
  187. MPR_LOG2(ERROR,"MprGetKeyValue:RegQueryValueEx(\"%ws\") failed %d\n",
  188. ValueName, status);
  189. *ValueString = NULL;
  190. return(FALSE);
  191. }
  192. //
  193. // Allocate buffer to receive the value string.
  194. //
  195. maxValueLen += sizeof(TCHAR);
  196. TempValue = (LPTSTR) LocalAlloc(LMEM_FIXED, maxValueLen);
  197. if(TempValue == NULL) {
  198. MPR_LOG(ERROR,"MprGetKeyValue:LocalAlloc failed\n", 0);
  199. *ValueString = NULL;
  200. return(FALSE);
  201. }
  202. //
  203. // Read the value.
  204. //
  205. status = RegQueryValueEx(
  206. KeyHandle, // hKey
  207. ValueName, // lpValueName
  208. NULL, // lpTitleIndex
  209. &ValueType, // lpType
  210. (LPBYTE)TempValue, // lpData
  211. &maxValueLen); // lpcbData
  212. if (status != NO_ERROR) {
  213. MPR_LOG2(ERROR,"MprGetKeyValue:RegQueryValueEx(\"%ws\") failed %d\n",
  214. ValueName, status);
  215. LocalFree(TempValue);
  216. *ValueString = NULL;
  217. return(FALSE);
  218. }
  219. //
  220. // Make sure the value is null-terminated. Strings obtained from
  221. // the registry may or may not be null-terminated.
  222. //
  223. TempValue [ maxValueLen / sizeof(TCHAR) ] = 0;
  224. //========================================================
  225. //
  226. // If the value is of REG_EXPAND_SZ type, then expand it.
  227. //
  228. //========================================================
  229. if (ValueType != REG_EXPAND_SZ) {
  230. *ValueString = TempValue;
  231. return(TRUE);
  232. }
  233. //
  234. // If the ValueType is REG_EXPAND_SZ, then we must call the
  235. // function to expand environment variables.
  236. //
  237. MPR_LOG(TRACE,"MprGetKeyValue: Must expand the string for "
  238. FORMAT_LPTSTR "\n", ValueName);
  239. //
  240. // Make the first call just to get the number of characters that
  241. // will be returned.
  242. //
  243. NumRequired = ExpandEnvironmentStrings (TempValue,Temp, 1);
  244. if (NumRequired > 1) {
  245. *ValueString = (LPTSTR) LocalAlloc(LPTR, (NumRequired+1)*sizeof(TCHAR));
  246. if (*ValueString == NULL) {
  247. MPR_LOG(ERROR, "MprGetKeyValue: LocalAlloc of numChar= "
  248. FORMAT_DWORD " failed \n",NumRequired );
  249. (void) LocalFree(TempValue);
  250. return(FALSE);
  251. }
  252. CharsReturned = ExpandEnvironmentStrings (
  253. TempValue,
  254. *ValueString,
  255. NumRequired);
  256. (void) LocalFree(TempValue);
  257. if (CharsReturned > NumRequired || CharsReturned == 0) {
  258. MPR_LOG(ERROR, "MprGetKeyValue: ExpandEnvironmentStrings "
  259. " failed for " FORMAT_LPTSTR " \n", ValueName);
  260. (void) LocalFree(*ValueString);
  261. *ValueString = NULL;
  262. return(FALSE);
  263. }
  264. //
  265. // Now insert the NUL terminator.
  266. //
  267. (*ValueString)[CharsReturned] = 0;
  268. }
  269. else {
  270. //
  271. // This call should have failed because of our ridiculously small
  272. // buffer size.
  273. //
  274. MPR_LOG(ERROR, "MprGetKeyValue: ExpandEnvironmentStrings "
  275. " Should have failed because we gave it a BufferSize=1\n",0);
  276. //
  277. // This could happen if the string was a single character long and
  278. // didn't really have any environment values to expand. In this
  279. // case, we return the TempValue buffer pointer.
  280. //
  281. *ValueString = TempValue;
  282. }
  283. return(TRUE);
  284. }
  285. BOOL
  286. MprGetKeyDwordValue(
  287. IN HKEY KeyHandle,
  288. IN LPCWSTR ValueName,
  289. OUT DWORD * Value
  290. )
  291. /*++
  292. Routine Description:
  293. This function takes a key handle and a value name, and returns a DWORD
  294. value that is associated with that name.
  295. Arguments:
  296. KeyHandle - This is a handle for the registry key that contains the value.
  297. ValueName - A pointer to a string that identifies the value being
  298. obtained. If this value does not have REG_DWORD type the function
  299. returns FALSE.
  300. Value - A pointer to a location that upon exit will contain the returned
  301. DWORD value.
  302. Return Value:
  303. TRUE - Success
  304. FALSE - A fatal error occured.
  305. --*/
  306. {
  307. DWORD dwSize = sizeof(DWORD);
  308. DWORD dwType;
  309. DWORD status = RegQueryValueEx(
  310. KeyHandle,
  311. ValueName,
  312. 0, // reserved
  313. &dwType, // type
  314. (LPBYTE) Value,
  315. &dwSize);
  316. if (status)
  317. {
  318. MPR_LOG2(ERROR,"MprGetKeyDwordValue: RegQueryValueEx(\"%ws\") failed %ld\n",
  319. ValueName, status);
  320. return FALSE;
  321. }
  322. else if (dwType != REG_DWORD || dwSize != sizeof(DWORD))
  323. {
  324. MPR_LOG3(ERROR,"MprGetKeyDwordValue: RegQueryValueEx(\"%ws\") returned "
  325. "type %ld, size %ld\n", ValueName, dwType, dwSize);
  326. return FALSE;
  327. }
  328. return TRUE;
  329. }
  330. LONG
  331. MprGetKeyNumberValue(
  332. IN HKEY KeyHandle,
  333. IN LPCWSTR ValueName,
  334. IN LONG Default
  335. )
  336. /*++
  337. Routine Description:
  338. This function takes a key handle and a value name, and returns a numeric
  339. value that is associated with that name. If an error occurs while
  340. retrieving the value, the specified Default value is returned.
  341. For compatibility, the behavior of this function is exactly the same as
  342. Win95's RegEntry::GetNumber function. The value is assumed to be a 4-byte
  343. type, such as REG_BINARY or REG_DWORD. If this is not the case, the
  344. function does exactly the same as Win95.
  345. Arguments:
  346. KeyHandle - This is a handle for the registry key that contains the value.
  347. ValueName - A pointer to a string that identifies the value being
  348. obtained.
  349. Default - Value to return if one could not be obtained from the registry.
  350. Return Value:
  351. Value retrieved from the registry, or default if an error occurs.
  352. --*/
  353. {
  354. LONG dwNumber;
  355. DWORD dwSize = sizeof(dwNumber);
  356. DWORD error = RegQueryValueEx(
  357. KeyHandle,
  358. ValueName,
  359. 0, // reserved
  360. NULL, // type
  361. (LPBYTE) &dwNumber,
  362. &dwSize);
  363. if (error)
  364. dwNumber = Default;
  365. return dwNumber;
  366. }
  367. BOOL
  368. MprGetKeyStringValue(
  369. IN HKEY KeyHandle,
  370. IN LPCWSTR ValueName,
  371. IN DWORD cchMaxValueLength,
  372. OUT LPWSTR *Value
  373. )
  374. /*++
  375. Routine Description:
  376. This function takes a key handle, a value name, and a max size and allocates/returns
  377. a string value that is associated with that name.
  378. Arguments:
  379. KeyHandle - This is a handle for the registry key that contains the value.
  380. ValueName - A pointer to a string that identifies the value being
  381. obtained. If this value does not have REG_SZ type the function
  382. returns FALSE.
  383. cchMaxValueLength - Size of the OUT buffer to allocate, in characters.
  384. Value - A pointer to a location that upon exit will contain the returned
  385. LPWSTR value.
  386. Return Value:
  387. TRUE - Success
  388. FALSE - A fatal error occured.
  389. --*/
  390. {
  391. DWORD status;
  392. DWORD dwType;
  393. DWORD dwSize = (cchMaxValueLength + 1) * sizeof(WCHAR);
  394. *Value = (LPWSTR) LocalAlloc(LMEM_ZEROINIT, dwSize);
  395. if (*Value == NULL)
  396. {
  397. return FALSE;
  398. }
  399. status = RegQueryValueEx(KeyHandle,
  400. ValueName,
  401. 0, // reserved
  402. &dwType, // type
  403. (LPBYTE) *Value,
  404. &dwSize);
  405. if (status || (dwSize % 2) != 0)
  406. {
  407. LocalFree(*Value);
  408. *Value = NULL;
  409. return FALSE;
  410. }
  411. if (dwType != REG_SZ)
  412. {
  413. //
  414. // Legacy -- MPR writes out a NULL username as a DWORD 0x0. Make sure
  415. // these values are NULL-terminated
  416. //
  417. (*Value)[cchMaxValueLength] = L'\0';
  418. return TRUE;
  419. }
  420. return TRUE;
  421. }
  422. DWORD
  423. MprEnumKey(
  424. IN HKEY KeyHandle,
  425. IN DWORD SubKeyIndex,
  426. OUT LPTSTR *SubKeyName,
  427. IN DWORD MaxSubKeyNameLen
  428. )
  429. /*++
  430. Routine Description:
  431. This function obtains a single name of a subkey from the registry.
  432. A key handle for the primary key is passed in. Subkeys are enumerated
  433. one-per-call with the passed in index indicating where we are in the
  434. enumeration.
  435. NOTE: This function allocates memory for the returned SubKeyName.
  436. Arguments:
  437. KeyHandle - Handle to the key whose sub keys are to be enumerated.
  438. SubKeyIndex - Indicates the number (index) of the sub key to be returned.
  439. SubKeyName - A pointer to the location where the pointer to the
  440. subkey name string is to be placed.
  441. MaxSubKeyNameLen - This is the length of the largest subkey. This value
  442. was obtained from calling MprGetKeyInfo. The length is in number
  443. of characters and does not include the NULL terminator.
  444. Return Value:
  445. WN_SUCCESS - The operation was successful.
  446. STATUS_NO_MORE_SUBKEYS - The SubKeyIndex value was larger than the
  447. number of subkeys.
  448. error returned from LocalAlloc
  449. --*/
  450. {
  451. DWORD status;
  452. FILETIME lastWriteTime;
  453. DWORD bufferSize;
  454. //
  455. // Allocate buffer to receive the SubKey Name.
  456. //
  457. // NOTE: Space is allocated for an extra character because in the case
  458. // of a drive name, we need to add the trailing colon.
  459. //
  460. bufferSize = (MaxSubKeyNameLen + 2) * sizeof(TCHAR);
  461. *SubKeyName = (LPTSTR) LocalAlloc(LMEM_FIXED, bufferSize);
  462. if(*SubKeyName == NULL) {
  463. MPR_LOG(ERROR,"MprEnumKey:LocalAlloc failed %d\n", GetLastError());
  464. return(WN_OUT_OF_MEMORY);
  465. }
  466. //
  467. // Get the Subkey name at that index.
  468. //
  469. status = RegEnumKeyEx(
  470. KeyHandle, // hKey
  471. SubKeyIndex, // dwIndex
  472. *SubKeyName, // lpName
  473. &bufferSize, // lpcbName
  474. NULL, // lpTitleIndex
  475. NULL, // lpClass
  476. NULL, // lpcbClass
  477. &lastWriteTime); // lpftLastWriteTime
  478. if (status != NO_ERROR) {
  479. MPR_LOG(ERROR,"MprEnumKey:RegEnumKeyEx failed %d\n",status);
  480. LocalFree(*SubKeyName);
  481. return(status);
  482. }
  483. return(WN_SUCCESS);
  484. }
  485. BOOL
  486. MprGetKeyInfo(
  487. IN HKEY KeyHandle,
  488. OUT LPDWORD TitleIndex OPTIONAL,
  489. OUT LPDWORD NumSubKeys,
  490. OUT LPDWORD MaxSubKeyLen,
  491. OUT LPDWORD NumValues OPTIONAL,
  492. OUT LPDWORD MaxValueLen
  493. )
  494. /*++
  495. Routine Description:
  496. Arguments:
  497. KeyHandle - Handle to the key for which we are to obtain information.
  498. NumSubKeys - This is a pointer to a location where the number
  499. of sub keys is to be placed.
  500. MaxSubKeyLen - This is a pointer to a location where the length of
  501. the longest subkey name is to be placed.
  502. NumValues - This is a pointer to a location where the number of
  503. key values is to be placed. This pointer is optional and can be
  504. NULL.
  505. MaxValueLen - This is a pointer to a location where the length of
  506. the longest data value is to be placed.
  507. Return Value:
  508. TRUE - The operation was successful.
  509. FALSE - A failure occured. The returned values are not to be believed.
  510. --*/
  511. {
  512. DWORD status;
  513. DWORD maxClassLength;
  514. DWORD numValueNames;
  515. DWORD maxValueNameLength;
  516. DWORD securityDescLength;
  517. FILETIME lastWriteTime;
  518. //
  519. // Get the Key Information
  520. //
  521. status = RegQueryInfoKey(
  522. KeyHandle,
  523. NULL, // Class
  524. NULL, // size of class buffer (in bytes)
  525. NULL, // DWORD to receive title index
  526. NumSubKeys, // number of subkeys
  527. MaxSubKeyLen, // length(chars-no null) of longest subkey name
  528. &maxClassLength, // length of longest subkey class string
  529. &numValueNames, // number of valueNames for this key
  530. &maxValueNameLength, // length of longest ValueName
  531. MaxValueLen, // length of longest value's data field
  532. &securityDescLength, // lpcbSecurityDescriptor
  533. &lastWriteTime); // the last time the key was modified
  534. if (status != 0)
  535. {
  536. MPR_LOG(ERROR,"MprGetKeyInfo: RegQueryInfoKey Error %d\n",status);
  537. return(FALSE);
  538. }
  539. if (NumValues != NULL) {
  540. *NumValues = numValueNames;
  541. }
  542. //
  543. // Support for title index has been removed from the Registry API.
  544. //
  545. if (TitleIndex != NULL) {
  546. *TitleIndex = 0;
  547. }
  548. return(TRUE);
  549. }
  550. BOOL
  551. MprFindDriveInRegistry (
  552. IN LPCTSTR DriveName,
  553. IN OUT LPTSTR *pRemoteName
  554. )
  555. /*++
  556. Routine Description:
  557. This function determines whether a particular re-directed drive
  558. name resides in the network connection section of the current user's
  559. registry path. If the drive is already "remembered" in this section,
  560. this function returns TRUE.
  561. Arguments:
  562. DriveName - A pointer to a string containing the name of the redirected
  563. drive.
  564. pRemoteName - If the DriveName is found in the registry, and if this
  565. is non-null, the remote name for the connection is read, and a
  566. pointer to the string is stored in this pointer location.
  567. If the remote name cannot be read from the registry, a NULL
  568. pointer is returned in this location.
  569. Return Value:
  570. TRUE - The redirected drive is "remembered in the registry".
  571. FALSE - The redirected drive is not saved in the registry.
  572. --*/
  573. {
  574. BOOL bStatus = TRUE;
  575. HKEY connectKey = NULL;
  576. HKEY subKey = NULL;
  577. LPWSTR KeyName = STACK_ALLOC(DriveName);
  578. if (KeyName == NULL) {
  579. return FALSE;
  580. }
  581. RemoveColon(KeyName, DriveName);
  582. //
  583. // Get a handle for the connection section of the user's registry
  584. // space.
  585. //
  586. if (!MprOpenKey(
  587. HKEY_CURRENT_USER,
  588. CONNECTION_KEY_NAME,
  589. &connectKey,
  590. DA_READ)) {
  591. MPR_LOG(ERROR,"MprFindDriveInRegistry: MprOpenKey Failed\n",0);
  592. return (FALSE);
  593. }
  594. if (!MprOpenKey(
  595. connectKey,
  596. KeyName,
  597. &subKey,
  598. DA_READ)) {
  599. MPR_LOG(TRACE,"MprFindDriveInRegistry: Drive %s Not Found\n",DriveName);
  600. bStatus = FALSE;
  601. }
  602. else {
  603. //
  604. // The drive was found in the registry, if the caller wants to have
  605. // the RemoteName, then get it.
  606. //
  607. if (pRemoteName != NULL) {
  608. //
  609. // Get the RemoteName (memory is allocated by this function)
  610. //
  611. if(!MprGetKeyValue(
  612. subKey,
  613. REMOTE_PATH_NAME,
  614. pRemoteName)) {
  615. MPR_LOG(TRACE,"MprFindDriveInRegistry: Could not read "
  616. "Remote path for Drive %ws \n",DriveName);
  617. pRemoteName = NULL;
  618. }
  619. }
  620. }
  621. if ( subKey )
  622. RegCloseKey(subKey);
  623. if ( connectKey )
  624. RegCloseKey(connectKey);
  625. return(bStatus);
  626. }
  627. DWORD
  628. I_MprSaveConn(
  629. IN HKEY HiveRoot,
  630. IN LPCWSTR ProviderName,
  631. IN DWORD ProviderType,
  632. IN LPCWSTR UserName,
  633. IN LPCWSTR LocalName,
  634. IN LPCWSTR RemoteName,
  635. IN DWORD ConnectionType,
  636. IN BYTE ProviderFlags,
  637. IN DWORD DeferFlags
  638. )
  639. /*++
  640. Routine Description:
  641. Writes the information about a connection to the network connection
  642. section of a user's registry path.
  643. NOTE: If connection information is already stored in the registry for
  644. this drive, the current information will be overwritten with the new
  645. information.
  646. Arguments:
  647. HiveRoot - A handle to the root of the user hive in which this
  648. information should be written, such as HKEY_CURRENT_USER.
  649. ProviderName - The provider that completed the connection.
  650. ProviderType - The provider type, if known. If not known, zero should
  651. be passed, and a type will not be written to the registry. (This
  652. is used by setup when upgrading from Win95 to NT.)
  653. UserName - The name of the user on whose behalf the connection was made.
  654. LocalName - The name of the local device that is redirected, with or
  655. without a trailing colon, such as "J" or "J:" or "LPT1".
  656. RemoteName - The network path to which the connection was made.
  657. ConnectionType - either RESOURCETYPE_DISK or RESOURCETYPE_PRINT.
  658. ProviderFlags - A byte of data to be saved along with the connection,
  659. and passed back to the provider when the connection is restored.
  660. DeferFlags - A DWORD to be saved in the connection's "Defer" value. If
  661. this is zero, the value is not stored.
  662. The meaning of the bits of this DWORD are as follows:
  663. DEFER_EXPLICIT_PASSWORD - a password was explicitly specified when
  664. the connection was made.
  665. DEFER_UNKNOWN - it is not known whether a password was explicitly
  666. specified when the connection was made.
  667. DEFER_DEFAULT_CRED - The provider believes that default creds were
  668. used when the connection was made.
  669. Return Value:
  670. ERROR_SUCCESS - If the operation was successful.
  671. Other Win32 errors - If the operation failed in any way. If a failure
  672. occurs, the information is not stored in the registry.
  673. --*/
  674. {
  675. HKEY connectKey;
  676. HKEY localDevHandle;
  677. LPCTSTR pUserName;
  678. DWORD status, IgnoredStatus;
  679. //
  680. // Remove the colon on the name since the registry doesn't like
  681. // this in a key name.
  682. //
  683. LPWSTR KeyName = STACK_ALLOC(LocalName);
  684. if (KeyName == NULL) {
  685. return ERROR_NOT_ENOUGH_MEMORY;
  686. }
  687. RemoveColon(KeyName, LocalName);
  688. //
  689. // Get a handle for the connection section of the user's registry
  690. // space.
  691. //
  692. if ((status = MprCreateRegKey(
  693. HiveRoot,
  694. CONNECTION_KEY_NAME,
  695. &connectKey)) != ERROR_SUCCESS) {
  696. MPR_LOG(ERROR,"I_MprSaveConn: \\HKEY_CURRENT_USER\\network "
  697. "could not be opened or created, error %ld\n", status);
  698. return(status);
  699. }
  700. //
  701. // Get (or create) the handle for the local name (without colon).
  702. //
  703. if ((status = MprCreateRegKey(
  704. connectKey,
  705. KeyName,
  706. &localDevHandle)) != ERROR_SUCCESS) {
  707. MPR_LOG(ERROR,"I_MprSaveConn: MprCreateRegKey Failed, "
  708. "error %ld\n", status);
  709. RegCloseKey(connectKey);
  710. return(status);
  711. }
  712. //
  713. // Now that the key is created, store away the appropriate values.
  714. //
  715. MPR_LOG(TRACE,"RememberConnection: Setting RemotePath\n",0);
  716. if((status = MprSetRegValue(
  717. localDevHandle,
  718. REMOTE_PATH_NAME,
  719. RemoteName,
  720. 0)) != ERROR_SUCCESS) {
  721. MPR_LOG(ERROR,
  722. "I_MprSaveConn: MprSetRegValueFailed %lu - RemotePath\n",status);
  723. goto CleanExit;
  724. }
  725. MPR_LOG(TRACE,"RememberConnection: Setting User\n",0);
  726. pUserName = UserName;
  727. if (UserName == NULL) {
  728. pUserName = TEXT("");
  729. }
  730. if((status = MprSetRegValue(
  731. localDevHandle,
  732. USER_NAME,
  733. pUserName,
  734. 0)) != ERROR_SUCCESS) {
  735. goto CleanExit;
  736. }
  737. MPR_LOG(TRACE,"RememberConnection: Setting ProviderName\n",0);
  738. if((status = MprSetRegValue(
  739. localDevHandle,
  740. PROVIDER_NAME,
  741. ProviderName,
  742. 0)) != ERROR_SUCCESS) {
  743. goto CleanExit;
  744. }
  745. if (ProviderType != 0)
  746. {
  747. MPR_LOG(TRACE,"RememberConnection: Setting ProviderType\n",0);
  748. if((status = MprSetRegValue(
  749. localDevHandle,
  750. PROVIDER_TYPE,
  751. NULL,
  752. ProviderType)) != ERROR_SUCCESS) {
  753. goto CleanExit;
  754. }
  755. }
  756. // else RegDeleteValue -- not done because ProviderType is 0 only
  757. // during upgrade, while writing to a fresh user hive
  758. MPR_LOG(TRACE,"RememberConnection: Setting ConnectionType\n",0);
  759. if((status = MprSetRegValue(
  760. localDevHandle,
  761. CONNECTION_TYPE,
  762. NULL,
  763. ConnectionType)) != ERROR_SUCCESS) {
  764. goto CleanExit;
  765. }
  766. if (ProviderFlags != 0)
  767. {
  768. MPR_LOG(TRACE,"RememberConnection: Setting ProviderFlags\n",0);
  769. if((status = MprSetRegValue(
  770. localDevHandle,
  771. PROVIDER_FLAGS,
  772. NULL,
  773. ProviderFlags)) != ERROR_SUCCESS) {
  774. goto CleanExit;
  775. }
  776. }
  777. // We can't roll this back if something fails after it, so we
  778. // must do this last
  779. if ((status = MprSaveDeferFlags(localDevHandle, DeferFlags))
  780. != ERROR_SUCCESS) {
  781. goto CleanExit;
  782. }
  783. //
  784. // Flush the new key, and then close the handle to it.
  785. //
  786. MPR_LOG(TRACE,"RememberConnection: Flushing Registry Key\n",0);
  787. IgnoredStatus = RegFlushKey(localDevHandle);
  788. if (IgnoredStatus != NO_ERROR) {
  789. MPR_LOG(ERROR,"RememberConnection: Flushing Registry Key Failed %ld\n",
  790. IgnoredStatus);
  791. }
  792. CleanExit:
  793. RegCloseKey(localDevHandle);
  794. if (status != ERROR_SUCCESS) {
  795. IgnoredStatus = RegDeleteKey(connectKey, KeyName);
  796. if (IgnoredStatus != NO_ERROR) {
  797. MPR_LOG(ERROR, "RememberConnection: RegDeleteKey Failed %d\n", IgnoredStatus);
  798. }
  799. }
  800. RegCloseKey(connectKey);
  801. return(status);
  802. }
  803. DWORD
  804. MprSaveDeferFlags(
  805. IN HKEY RegKey,
  806. IN DWORD DeferFlags
  807. )
  808. {
  809. DWORD status;
  810. if (DeferFlags == 0)
  811. {
  812. MPR_LOG0(TRACE,"Removing DeferFlags\n");
  813. status = RegDeleteValue(RegKey, DEFER_FLAGS);
  814. if (status == ERROR_FILE_NOT_FOUND)
  815. {
  816. status = ERROR_SUCCESS;
  817. }
  818. }
  819. else
  820. {
  821. MPR_LOG(TRACE,"Setting DeferFlags %#lx\n",DeferFlags);
  822. status = MprSetRegValue(
  823. RegKey,
  824. DEFER_FLAGS,
  825. NULL,
  826. DeferFlags);
  827. }
  828. return status;
  829. }
  830. DWORD
  831. MprSetRegValue(
  832. IN HKEY KeyHandle,
  833. IN LPTSTR ValueName,
  834. IN LPCTSTR ValueString,
  835. IN DWORD LongValue
  836. )
  837. /*++
  838. Routine Description:
  839. Stores a single ValueName and associated data in the registry for
  840. the key identified by the KeyHandle. The data associated with the
  841. value can either be a string or a 32-bit LONG. If the ValueString
  842. argument contains a pointer to a value, then the LongValue argument
  843. is ignored.
  844. Arguments:
  845. KeyHandle - Handle of the key for which the value entry is to be set.
  846. ValueName - Pointer to a string that contains the name of the value
  847. being set.
  848. ValueString - Pointer to a string that is to become the data stored
  849. at that value name. If this argument is not present, then the
  850. LongValue argument is the data stored at the value name. If this
  851. argument is present, then LongValue is ignored.
  852. LongValue - A LONG sized data value that is to be stored at the
  853. value name.
  854. Return Value:
  855. Win32 error from RegSetValueEx (0 = success)
  856. --*/
  857. {
  858. DWORD status;
  859. const BYTE * valueData;
  860. DWORD valueSize;
  861. DWORD valueType;
  862. if( ARGUMENT_PRESENT(ValueString)) {
  863. valueData = (const BYTE *)ValueString;
  864. valueSize = (wcslen(ValueString) + 1) * sizeof(WCHAR);
  865. valueType = REG_SZ;
  866. }
  867. else {
  868. valueData = (const BYTE *)&LongValue;
  869. valueSize = sizeof(DWORD);
  870. valueType = REG_DWORD;
  871. }
  872. status = RegSetValueEx(
  873. KeyHandle, // hKey
  874. ValueName, // lpValueName
  875. 0, // dwValueTitle (OPTIONAL)
  876. valueType, // dwType
  877. valueData, // lpData
  878. valueSize); // cbData
  879. if(status != NO_ERROR) {
  880. MPR_LOG3(ERROR,"MprSetRegValue: RegSetValueEx(%#lx \"%ws\") Failed %ld\n",
  881. KeyHandle, ValueName, status);
  882. }
  883. return(status);
  884. }
  885. DWORD
  886. MprCreateRegKey(
  887. IN HKEY BaseKeyHandle,
  888. IN LPCTSTR KeyName,
  889. OUT PHKEY KeyHandlePtr
  890. )
  891. /*++
  892. Routine Description:
  893. Creates a key in the registry at the location described by KeyName.
  894. Arguments:
  895. BaseKeyHandle - This is a handle for the base (parent) key - where the
  896. subkey is to be created.
  897. KeyName - This is a pointer to a string that describes the path to the
  898. key that is to be created.
  899. KeyHandle - This is a pointer to a location where the the handle for the
  900. newly created key is to be placed.
  901. Return Value:
  902. Win32 error from RegCreateKeyEx (0 = success)
  903. Note:
  904. --*/
  905. {
  906. DWORD status;
  907. DWORD disposition;
  908. //
  909. // Create the new key.
  910. //
  911. status = RegCreateKeyEx(
  912. BaseKeyHandle, // hKey
  913. KeyName, // lpSubKey
  914. 0L, // dwTitleIndex
  915. TEXT("GenericClass"), // lpClass
  916. 0, // ulOptions
  917. KEY_WRITE, // samDesired (desired access)
  918. NULL, // lpSecurityAttrubutes (Security Descriptor)
  919. KeyHandlePtr, // phkResult
  920. &disposition); // lpulDisposition
  921. if (status != NO_ERROR) {
  922. MPR_LOG3(ERROR,"MprCreateRegKey: RegCreateKeyEx(%#lx, \"%ws\") failed %d\n",
  923. BaseKeyHandle, KeyName, status);
  924. }
  925. else {
  926. MPR_LOG(TRACE,"MprCreateRegKey: Disposition = 0x%x\n",disposition);
  927. }
  928. return(status);
  929. }
  930. BOOL
  931. MprReadConnectionInfo(
  932. IN HKEY KeyHandle,
  933. IN LPCTSTR DriveName,
  934. IN DWORD Index,
  935. OUT LPDWORD ProviderFlags,
  936. OUT LPDWORD DeferFlags,
  937. OUT LPTSTR *UserNamePtr,
  938. OUT LPNETRESOURCEW NetResource,
  939. OUT HKEY *SubKeyHandleOut,
  940. IN DWORD MaxSubKeyLen
  941. )
  942. /*++
  943. Routine Description:
  944. This function reads the data associated with a connection key.
  945. Buffers are allocated to store:
  946. UserName, RemoteName, LocalName, Provider
  947. Pointers to those buffers are returned.
  948. Also the connection type is read and stored in the NetResource structure.
  949. If the provider type is found in the registry, and a matching provider
  950. type is found in the GlobalProviderInfo array, the provider name is not
  951. read from the registry. Instead it is read from the GlobalProviderInfo
  952. array.
  953. If the provider name is read from the registry and a matching provider
  954. name is found in the GlobalProviderInfo array, the provider type is
  955. written to the registry.
  956. Arguments:
  957. KeyHandle - This is an already opened handle to the key whose
  958. sub-keys are to be enumerated.
  959. DriveName - This is the local name of the drive (eg. "f:") for which
  960. the connection information is to be obtained. If DriveName is
  961. NULL, then the Index is used to enumerate the keyname. Then
  962. that keyname is used.
  963. Index - This is the index that identifies the subkey for which we
  964. would like to receive information.
  965. ProviderFlags - This is a pointer to a location where the ProviderFlags
  966. value stored with the connection will be placed. If this value
  967. cannot be retrieved, 0 will be placed here.
  968. DeferFlags - This is a pointer to a location where the DeferFlags
  969. value stored with the connection will be placed. If this value
  970. cannot be retrieved, 0 will be placed here.
  971. UserNamePtr - This is a pointer to a location where the pointer to the
  972. UserName string is to be placed. If there is no user name, a
  973. NULL pointer will be returned.
  974. NetResource - This is a pointer to a NETRESOURCE structure where
  975. information such as lpRemoteName, lpLocalName, lpProvider, and Type
  976. are to be placed.
  977. SubKeyHandleOut - This is a pointer to a location where the handle to
  978. the subkey that holds information about this connection will be
  979. placed. This may be NULL. If it is not NULL the caller must close
  980. the handle.
  981. Return Value:
  982. Note:
  983. --*/
  984. {
  985. DWORD status = NO_ERROR;
  986. LPTSTR driveName = NULL;
  987. HKEY subKeyHandle = NULL;
  988. DWORD cbData;
  989. DWORD ProviderType = 0;
  990. LPPROVIDER Provider;
  991. //
  992. // Initialize the Pointers that are to be updated.
  993. //
  994. *UserNamePtr = NULL;
  995. NetResource->lpLocalName = NULL;
  996. NetResource->lpRemoteName = NULL;
  997. NetResource->lpProvider = NULL;
  998. NetResource->dwType = 0L;
  999. //
  1000. // If we don't have a DriveName, then get one by enumerating the
  1001. // next key name.
  1002. //
  1003. if (DriveName == NULL) {
  1004. //
  1005. // Get the name of a subkey of the network connection key.
  1006. // (memory is allocated by this function).
  1007. //
  1008. status = MprEnumKey(KeyHandle, Index, &driveName, MaxSubKeyLen);
  1009. if (status != WN_SUCCESS) {
  1010. return(FALSE);
  1011. }
  1012. }
  1013. else {
  1014. //
  1015. // We have a drive name, alloc new space and copy it to that
  1016. // location.
  1017. //
  1018. driveName = (LPTSTR) LocalAlloc(LMEM_FIXED, (wcslen(DriveName) + 1) * sizeof(WCHAR));
  1019. if (driveName == NULL) {
  1020. MPR_LOG(ERROR, "MprReadConnectionInfo: Local Alloc Failed %d\n",
  1021. GetLastError());
  1022. return(FALSE);
  1023. }
  1024. RemoveColon(driveName, DriveName);
  1025. }
  1026. MPR_LOG1(TRACE,"MprReadConnectionInfo: LocalName = %ws\n",driveName);
  1027. //
  1028. // Open the sub-key
  1029. //
  1030. if (!MprOpenKey(
  1031. KeyHandle,
  1032. driveName,
  1033. &subKeyHandle,
  1034. DA_WRITE)){
  1035. status = WN_BAD_PROFILE;
  1036. MPR_LOG1(TRACE,"MprReadConnectionInfo: Could not open %ws Key\n",driveName);
  1037. goto CleanExit;
  1038. }
  1039. //
  1040. // Add the trailing colon to the driveName.
  1041. //
  1042. cbData = wcslen(driveName);
  1043. driveName[cbData] = TEXT(':');
  1044. driveName[cbData+1] = TEXT('\0');
  1045. //
  1046. // Store the drive name in the return structure.
  1047. //
  1048. NetResource->lpLocalName = driveName;
  1049. //
  1050. // Get the RemoteName (memory is allocated by this function)
  1051. //
  1052. if(!MprGetKeyValue(
  1053. subKeyHandle,
  1054. REMOTE_PATH_NAME,
  1055. &(NetResource->lpRemoteName))) {
  1056. status = WN_BAD_PROFILE;
  1057. MPR_LOG0(TRACE,"MprReadConnectionInfo: Could not get RemoteName\n");
  1058. goto CleanExit;
  1059. }
  1060. //
  1061. // Get the UserName (memory is allocated by this function)
  1062. //
  1063. if(!MprGetKeyStringValue(
  1064. subKeyHandle,
  1065. USER_NAME,
  1066. CRED_MAX_USERNAME_LENGTH,
  1067. UserNamePtr))
  1068. {
  1069. status = WN_BAD_PROFILE;
  1070. MPR_LOG0(TRACE,"MprReadConnectionInfo: Could not get UserName\n");
  1071. goto CleanExit;
  1072. }
  1073. else
  1074. {
  1075. //
  1076. // If there is no user name (the length is 0), then set the
  1077. // return pointer to NULL.
  1078. //
  1079. if (wcslen(*UserNamePtr) == 0) {
  1080. LocalFree(*UserNamePtr);
  1081. *UserNamePtr = NULL;
  1082. }
  1083. }
  1084. //
  1085. // Get the Provider Type and load the providers if necessary. Both
  1086. // MprGetConnection and a remembered enumeration can make it to this
  1087. // point in this state and we don't want to do a Level 2
  1088. // initialization every time one of those functions is called simply
  1089. // because this case _might_ be hit. For example, calling
  1090. // MprGetConnection on an unconnected drive letter may or may not
  1091. // have a name associated with it in the registry. If so, there's
  1092. // no need to load the providers to get information from them. This
  1093. // is equivalent to INIT_IF_NECESSARY(NETWORK_LEVEL,status)
  1094. //
  1095. if (MprGetKeyDwordValue(
  1096. subKeyHandle,
  1097. PROVIDER_TYPE,
  1098. &ProviderType)
  1099. &&
  1100. (MprLevel2Init(NETWORK_LEVEL) == WN_SUCCESS)
  1101. &&
  1102. ((Provider = MprFindProviderByType(ProviderType)) != NULL))
  1103. {
  1104. MPR_LOG(RESTORE,"MprReadConnectionInfo: Found recognized provider type %#lx\n",
  1105. ProviderType);
  1106. //
  1107. // Got a recognized provider type from the registry.
  1108. // If we have a name for this provider in memory, use it, rather than
  1109. // reading the name from the registry.
  1110. // (memory is allocated for the name)
  1111. //
  1112. if (Provider->Resource.lpProvider != NULL)
  1113. {
  1114. NetResource->lpProvider =
  1115. (LPWSTR) LocalAlloc(0, (wcslen(Provider->Resource.lpProvider) + 1) * sizeof(WCHAR));
  1116. if (NetResource->lpProvider == NULL)
  1117. {
  1118. status = WN_BAD_PROFILE;
  1119. MPR_LOG(RESTORE,"MprReadConnectionInfo: LocalAlloc failed %ld\n",
  1120. GetLastError());
  1121. goto CleanExit;
  1122. }
  1123. wcscpy(NetResource->lpProvider, Provider->Resource.lpProvider);
  1124. }
  1125. }
  1126. //
  1127. // If we haven't got a provider name yet, try to read it from the registry.
  1128. // (Memory is allocated by this function.)
  1129. // This could legitimately happen in 2 cases:
  1130. // (1) We are reading a profile that was created by a Windows NT 3.51 or
  1131. // earlier machine and has not yet been converted to a 4.0 or later
  1132. // profile. Windows NT versions 3.51 and earlier wrote only the provider
  1133. // name to the registry, not the type.
  1134. // (2) We are reading a floating profile that was written by another
  1135. // machine which has a network provider installed that isn't installed on
  1136. // this machine. Or, a network provider was de-installed from this
  1137. // machine.
  1138. //
  1139. if (NetResource->lpProvider == NULL)
  1140. {
  1141. if(!MprGetKeyValue(
  1142. subKeyHandle,
  1143. PROVIDER_NAME,
  1144. &(NetResource->lpProvider)))
  1145. {
  1146. status = WN_BAD_PROFILE;
  1147. MPR_LOG0(RESTORE,"MprReadConnectionInfo: Could not get ProviderName\n");
  1148. goto CleanExit;
  1149. }
  1150. //
  1151. // Got a provider name from the registry.
  1152. // If we didn't read a provider type from the registry, but we
  1153. // recognize the provider name, write the type now for future use.
  1154. // (This would occur in case (1) above.)
  1155. // Failure to write the type is ignored.
  1156. // (Pathological cases in which we get an unrecognized type but a
  1157. // recognized name are left untouched.)
  1158. // Since it's possible to get to this point without having the
  1159. // providers loaded, we'll init if necessary here (see reasoning
  1160. // above). This is equivalent to INIT_IF_NECESSARY(NETWORK_LEVEL,status)
  1161. //
  1162. status = MprLevel2Init(NETWORK_LEVEL);
  1163. if (status != WN_SUCCESS) {
  1164. goto CleanExit;
  1165. }
  1166. Provider = MprFindProviderByName(NetResource->lpProvider);
  1167. if (Provider != NULL && Provider->Type != 0 && ProviderType == 0)
  1168. {
  1169. MPR_LOG2(RESTORE,"MprReadConnectionInfo: Setting ProviderType %#lx for %ws\n",
  1170. Provider->Type, driveName);
  1171. status = MprSetRegValue(
  1172. subKeyHandle,
  1173. PROVIDER_TYPE,
  1174. NULL,
  1175. Provider->Type);
  1176. if (status != ERROR_SUCCESS)
  1177. {
  1178. MPR_LOG(RESTORE,"MprReadConnectionInfo: Couldn't set ProviderType, %ld\n",
  1179. status);
  1180. }
  1181. }
  1182. }
  1183. //
  1184. // Get the ProviderFlags (failure is ignored)
  1185. //
  1186. cbData = sizeof(DWORD);
  1187. status = RegQueryValueEx(
  1188. subKeyHandle, // hKey
  1189. PROVIDER_FLAGS, // lpValueName
  1190. NULL, // lpTitleIndex
  1191. NULL, // lpType
  1192. (LPBYTE)ProviderFlags, // lpData
  1193. &cbData); // lpcbData
  1194. if (status == NO_ERROR) {
  1195. MPR_LOG2(RESTORE,"MprReadConnectionInfo: Got ProviderFlags %#lx for %ws\n",
  1196. *ProviderFlags, driveName);
  1197. }
  1198. else {
  1199. *ProviderFlags = 0;
  1200. }
  1201. //
  1202. // Get the DeferFlags (failure is ignored)
  1203. //
  1204. if (MprGetKeyDwordValue(
  1205. subKeyHandle,
  1206. DEFER_FLAGS,
  1207. DeferFlags
  1208. ))
  1209. {
  1210. MPR_LOG2(RESTORE,"MprReadConnectionInfo: Got DeferFlags %#lx for %ws\n",
  1211. *DeferFlags, driveName);
  1212. }
  1213. else
  1214. {
  1215. *DeferFlags = 0;
  1216. }
  1217. //
  1218. // Get the Connection Type
  1219. //
  1220. cbData = sizeof(DWORD);
  1221. status = RegQueryValueEx(
  1222. subKeyHandle, // hKey
  1223. CONNECTION_TYPE, // lpValueName
  1224. NULL, // lpTitleIndex
  1225. NULL, // lpType
  1226. (LPBYTE)&(NetResource->dwType), // lpData
  1227. &cbData); // lpcbData
  1228. if (status != NO_ERROR) {
  1229. MPR_LOG1(ERROR,"MprReadConnectionInfo:RegQueryValueEx failed %d\n",
  1230. status);
  1231. MPR_LOG0(TRACE,"MprReadConnectionInfo: Could not get ConnectionType\n");
  1232. status = WN_BAD_PROFILE;
  1233. }
  1234. CleanExit:
  1235. if (status != NO_ERROR) {
  1236. LocalFree(driveName);
  1237. LocalFree(NetResource->lpRemoteName);
  1238. LocalFree(*UserNamePtr);
  1239. LocalFree(NetResource->lpProvider);
  1240. NetResource->lpLocalName = NULL;
  1241. NetResource->lpRemoteName = NULL;
  1242. NetResource->lpProvider = NULL;
  1243. *UserNamePtr = NULL;
  1244. if (subKeyHandle != NULL) {
  1245. RegCloseKey(subKeyHandle);
  1246. }
  1247. return(FALSE);
  1248. }
  1249. else {
  1250. if (SubKeyHandleOut == NULL) {
  1251. RegCloseKey(subKeyHandle);
  1252. }
  1253. else {
  1254. *SubKeyHandleOut = subKeyHandle;
  1255. }
  1256. return(TRUE);
  1257. }
  1258. }
  1259. VOID
  1260. MprForgetRedirConnection(
  1261. IN LPCTSTR lpName
  1262. )
  1263. /*++
  1264. Routine Description:
  1265. This function removes a key for the specified redirected device from
  1266. the current users portion of the registry.
  1267. Arguments:
  1268. lpName - This is a pointer to a redirected device name.
  1269. Return Value:
  1270. Note:
  1271. --*/
  1272. {
  1273. DWORD status;
  1274. HKEY connectKey;
  1275. MPR_LOG(TRACE,"In MprForgetConnection for %s\n", lpName);
  1276. LPWSTR KeyName = STACK_ALLOC(lpName);
  1277. if (KeyName == NULL) {
  1278. return;
  1279. }
  1280. RemoveColon(KeyName, lpName);
  1281. //
  1282. // Get a handle for the connection section of the user's registry
  1283. // space.
  1284. //
  1285. if (!MprOpenKey(
  1286. HKEY_CURRENT_USER,
  1287. CONNECTION_KEY_NAME,
  1288. &connectKey,
  1289. DA_READ)) {
  1290. MPR_LOG(ERROR,"WNetForgetRedirCon: MprOpenKey #1 Failed\n",0);
  1291. return;
  1292. }
  1293. status = RegDeleteKey(connectKey, KeyName);
  1294. if (status != NO_ERROR) {
  1295. MPR_LOG(ERROR, "WNetForgetRedirCon: NtDeleteKey Failed %d\n", status);
  1296. }
  1297. //
  1298. // Flush the connect key, and then close the handle to it.
  1299. //
  1300. MPR_LOG(TRACE,"ForgetRedirConnection: Flushing Connection Key\n",0);
  1301. status = RegFlushKey(connectKey);
  1302. if (status != NO_ERROR) {
  1303. MPR_LOG(ERROR,"RememberConnection: Flushing Connection Key Failed %ld\n",
  1304. status);
  1305. }
  1306. RegCloseKey(connectKey);
  1307. return;
  1308. }
  1309. BOOL
  1310. MprGetRemoteName(
  1311. IN LPTSTR lpLocalName,
  1312. IN OUT LPDWORD lpBufferSize,
  1313. OUT LPTSTR lpRemoteName,
  1314. OUT LPDWORD lpStatus
  1315. )
  1316. /*++
  1317. Routine Description:
  1318. This fuction Looks in the CURRENT_USER portion of the registry for
  1319. connection information related to the lpLocalName passed in.
  1320. Arguments:
  1321. lpLocalName - Pointer to a string containing the name of the device to
  1322. look up.
  1323. lpBufferSize - Pointer to a the size information for the buffer.
  1324. On input, this contains the size of the buffer passed in.
  1325. if lpStatus contain WN_MORE_DATA, this will contain the
  1326. buffer size required to obtain the full string.
  1327. lpRemoteName - Pointer to a buffer where the remote name string is
  1328. to be placed.
  1329. lpStatus - Pointer to a location where the proper return code is to
  1330. be placed in the case where the connection information exists.
  1331. Return Value:
  1332. TRUE - If the connection information exists.
  1333. FALSE - If the connection information does not exist. When FALSE is
  1334. returned, none of output parameters are valid.
  1335. --*/
  1336. {
  1337. HKEY connectKey;
  1338. DWORD numSubKeys;
  1339. DWORD maxSubKeyLen;
  1340. DWORD maxValueLen;
  1341. DWORD status;
  1342. DWORD ProviderFlags;
  1343. DWORD DeferFlags;
  1344. NETRESOURCEW netResource;
  1345. LPTSTR userName;
  1346. //
  1347. // Get a handle for the connection section of the user's registry
  1348. // space.
  1349. //
  1350. if (!MprOpenKey(
  1351. HKEY_CURRENT_USER,
  1352. CONNECTION_KEY_NAME,
  1353. &connectKey,
  1354. DA_READ)) {
  1355. MPR_LOG(ERROR,"WNetGetConnection: MprOpenKey Failed\n",0);
  1356. return(FALSE);
  1357. }
  1358. if(!MprGetKeyInfo(
  1359. connectKey,
  1360. NULL,
  1361. &numSubKeys,
  1362. &maxSubKeyLen,
  1363. NULL,
  1364. &maxValueLen)) {
  1365. MPR_LOG(ERROR,"WNetGetConnection: MprGetKeyInfo Failed\n",0);
  1366. RegCloseKey(connectKey);
  1367. return(FALSE);
  1368. }
  1369. //
  1370. // Read the connection information.
  1371. // NOTE: This function allocates buffers for UserName and the
  1372. // following strings in the net resource structure:
  1373. // lpRemoteName,
  1374. // lpLocalName,
  1375. // lpProvider
  1376. //
  1377. if (MprReadConnectionInfo(
  1378. connectKey,
  1379. lpLocalName,
  1380. 0,
  1381. &ProviderFlags,
  1382. &DeferFlags,
  1383. &userName,
  1384. &netResource,
  1385. NULL,
  1386. maxSubKeyLen)) {
  1387. //
  1388. // The read succeeded. Therefore we have connection information.
  1389. //
  1390. if (*lpBufferSize >= (wcslen(netResource.lpRemoteName) + 1) * sizeof(WCHAR)) {
  1391. __try {
  1392. wcscpy(lpRemoteName, netResource.lpRemoteName);
  1393. }
  1394. __except(EXCEPTION_EXECUTE_HANDLER) {
  1395. status = GetExceptionCode();
  1396. if (status != EXCEPTION_ACCESS_VIOLATION) {
  1397. MPR_LOG(ERROR,"WNetGetConnection:Unexpected Exception 0x%lx\n",status);
  1398. }
  1399. status = WN_BAD_POINTER;
  1400. }
  1401. if (status != WN_BAD_POINTER) {
  1402. //
  1403. // We successfully copied the remote name to the users
  1404. // buffer without an error.
  1405. //
  1406. status = WN_SUCCESS;
  1407. }
  1408. }
  1409. else {
  1410. *lpBufferSize = (wcslen(netResource.lpRemoteName) + 1) * sizeof(WCHAR);
  1411. status = WN_MORE_DATA;
  1412. }
  1413. //
  1414. // Free up the resources allocated by MprReadConnectionInfo.
  1415. //
  1416. LocalFree(userName);
  1417. LocalFree(netResource.lpLocalName);
  1418. LocalFree(netResource.lpRemoteName);
  1419. LocalFree(netResource.lpProvider);
  1420. *lpStatus = status;
  1421. RegCloseKey(connectKey);
  1422. return(TRUE);
  1423. }
  1424. else {
  1425. //
  1426. // The read did not succeed.
  1427. //
  1428. RegCloseKey(connectKey);
  1429. return(FALSE);
  1430. }
  1431. }
  1432. DWORD
  1433. MprGetPrintKeyInfo(
  1434. HKEY KeyHandle,
  1435. LPDWORD NumValueNames,
  1436. LPDWORD MaxValueNameLength,
  1437. LPDWORD MaxValueLen)
  1438. /*++
  1439. Routine Description:
  1440. This function reads the data associated with a print reconnection key.
  1441. Arguments:
  1442. KeyHandle - This is an already opened handle to the key whose
  1443. info is rto be queried.
  1444. NumValueNames - Used to return the number of values
  1445. MaxValueNameLength - Used to return the max value name length
  1446. MaxValueLen - Used to return the max value data length
  1447. Return Value:
  1448. 0 if success. Win32 error otherwise.
  1449. Note:
  1450. --*/
  1451. {
  1452. DWORD err;
  1453. DWORD maxClassLength;
  1454. DWORD securityDescLength;
  1455. DWORD NumSubKeys ;
  1456. DWORD MaxSubKeyLen ;
  1457. FILETIME lastWriteTime;
  1458. //
  1459. // Get the Key Information
  1460. //
  1461. err = RegQueryInfoKey(
  1462. KeyHandle,
  1463. NULL, // Class
  1464. NULL, // size of class buffer (in bytes)
  1465. NULL, // DWORD to receive title index
  1466. &NumSubKeys, // number of subkeys
  1467. &MaxSubKeyLen, // length of longest subkey name
  1468. &maxClassLength, // length of longest subkey class string
  1469. NumValueNames, // number of valueNames for this key
  1470. MaxValueNameLength, // length of longest ValueName
  1471. MaxValueLen, // length of longest value's data field
  1472. &securityDescLength, // lpcbSecurityDescriptor
  1473. &lastWriteTime); // the last time the key was modified
  1474. return(err);
  1475. }
  1476. DWORD
  1477. MprForgetPrintConnection(
  1478. IN LPTSTR lpName
  1479. )
  1480. /*++
  1481. Routine Description:
  1482. This function removes a rememembered print reconnection value.
  1483. Arguments:
  1484. lpName - name of path to forget
  1485. Return Value:
  1486. 0 if success. Win32 error otherwise.
  1487. Note:
  1488. --*/
  1489. {
  1490. HKEY hKey ;
  1491. DWORD err ;
  1492. if (!MprOpenKey(
  1493. HKEY_CURRENT_USER,
  1494. PRINT_CONNECTION_KEY_NAME,
  1495. &hKey,
  1496. DA_WRITE))
  1497. {
  1498. return (GetLastError()) ;
  1499. }
  1500. err = RegDeleteValue(hKey,
  1501. lpName) ;
  1502. RegCloseKey(hKey) ;
  1503. return err ;
  1504. }