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
1947 lines
53 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
MPRREG.CXX
|
|
|
|
Abstract:
|
|
|
|
Contains functions used by MPR to manipulate the registry.
|
|
MprOpenKey
|
|
MprGetKeyValue
|
|
MprEnumKey
|
|
MprGetKeyInfo
|
|
MprFindDriveInRegistry
|
|
I_MprSaveConn
|
|
MprSaveDeferFlags
|
|
MprSetRegValue
|
|
MprCreateRegKey
|
|
MprReadConnectionInfo
|
|
MprForgetRedirConnection
|
|
MprGetRemoteName
|
|
|
|
|
|
QUESTIONS:
|
|
1) Do I need to call RegFlushKey after creating a new key?
|
|
|
|
Author:
|
|
|
|
Dan Lafferty (danl) 12-Dec-1991
|
|
|
|
Environment:
|
|
|
|
User Mode - Win32
|
|
|
|
|
|
Revision History:
|
|
|
|
21-Feb-1997 AnirudhS
|
|
Change MprRememberConnection to I_MprSaveConn and MprSaveDeferFlags
|
|
for use by setup and by DEFER_UNKNOWN.
|
|
|
|
12-Jun-1996 AnirudhS
|
|
Got rid of the REMOVE_COLON/RESTORE_COLON scheme for converting
|
|
device names to registry key names, since it caused writes to
|
|
read-only input parameters.
|
|
|
|
08-Mar-1996 AnirudhS
|
|
Save the provider type, not the provider name, for persistent
|
|
connections. Fix old heap corruption bugs that show up when the
|
|
user profile contains incomplete info.
|
|
|
|
16-Jun-1995 AnirudhS
|
|
Returned DWORDs rather than BOOLs from some functions; changed some
|
|
formal parameters from LPWSTR to LPCWSTR.
|
|
|
|
24-Nov-1992 Danl
|
|
Fixed compiler warnings by always using HKEY rather than HANDLE.
|
|
|
|
03-Sept-1992 Danl
|
|
MprGetRemoteName: Changed ERROR_BUFFER_OVERFLOW to WN_MORE_DATA.
|
|
|
|
12-Dec-1991 danl
|
|
Created
|
|
|
|
--*/
|
|
|
|
//
|
|
// Includes
|
|
//
|
|
#include "precomp.hxx"
|
|
#include <malloc.h> // _alloca
|
|
#include <debugfmt.h> // FORMAT_LPTSTR
|
|
#include <wincred.h> // CRED_MAX_USERNAME_LENGTH
|
|
|
|
|
|
//
|
|
// Macros
|
|
//
|
|
|
|
//
|
|
// STACK_ALLOC
|
|
//
|
|
// Allocates space on the stack for a copy of an input string. The result
|
|
// could be NULL if the string is too long to be copied on the stack.
|
|
//
|
|
#define STACK_ALLOC(str) ((LPWSTR) _alloca((wcslen(str)+1)*sizeof(WCHAR)))
|
|
|
|
|
|
|
|
VOID
|
|
RemoveColon(
|
|
LPWSTR pszCopy,
|
|
LPCWSTR pszSource
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function makes a copy of a string and searches through the copy
|
|
for a colon. If a colon is found, it is replaced by a '\0'.
|
|
|
|
Arguments:
|
|
|
|
pszCopy - Pointer to the space for the copy.
|
|
|
|
pszSource - Pointer to the source string.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
wcscpy(pszCopy, pszSource);
|
|
WCHAR * pColon = wcschr(pszCopy, L':');
|
|
if (pColon != NULL)
|
|
{
|
|
*pColon = L'\0';
|
|
}
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
MprOpenKey(
|
|
IN HKEY hKey,
|
|
IN LPTSTR lpSubKey,
|
|
OUT PHKEY phKeyHandle,
|
|
IN DWORD desiredAccess
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function opens a handle to a key inside the registry. The major
|
|
handle and the path to the subkey are required as input.
|
|
|
|
Arguments:
|
|
|
|
hKey - This is one of the well-known root key handles for the portion
|
|
of the registry of interest.
|
|
|
|
lpSubKey - A pointer a string containing the path to the subkey.
|
|
|
|
phKeyHandle - A pointer to the location where the handle to the subkey
|
|
is to be placed.
|
|
|
|
desiredAccess - Desired Access (Either KEY_READ or KEY_WRITE or both).
|
|
|
|
Return Value:
|
|
|
|
TRUE - The operation was successful
|
|
|
|
FALSE - The operation was not successful.
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
DWORD status;
|
|
REGSAM samDesired = KEY_READ;
|
|
HKEY HKCU ;
|
|
|
|
if(desiredAccess & DA_WRITE) {
|
|
samDesired = KEY_READ | KEY_WRITE;
|
|
}
|
|
else if (desiredAccess & DA_DELETE) {
|
|
samDesired = DELETE;
|
|
}
|
|
|
|
HKCU = NULL ;
|
|
|
|
if ( hKey == HKEY_CURRENT_USER ) {
|
|
status = RegOpenCurrentUser(
|
|
MAXIMUM_ALLOWED,
|
|
&HKCU );
|
|
|
|
if ( status != 0 )
|
|
{
|
|
return FALSE ;
|
|
}
|
|
|
|
hKey = HKCU ;
|
|
}
|
|
|
|
status = RegOpenKeyEx(
|
|
hKey, // hKey
|
|
lpSubKey, // lpSubKey
|
|
0L, // ulOptions (reserved)
|
|
samDesired, // desired access security mask
|
|
phKeyHandle); // Newly Opened Key Handle
|
|
|
|
if ( HKCU )
|
|
{
|
|
RegCloseKey( HKCU );
|
|
}
|
|
|
|
if (status != NO_ERROR) {
|
|
MPR_LOG3(ERROR,"MprOpenKey: RegOpenKeyEx(%#lx \"%ws\") failed %d\n",
|
|
hKey, lpSubKey, status);
|
|
return (FALSE);
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOL
|
|
MprGetKeyValue(
|
|
IN HKEY KeyHandle,
|
|
IN LPTSTR ValueName,
|
|
OUT LPTSTR *ValueString
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function takes a key handle and a value name, and returns a value
|
|
string that is associated with that name.
|
|
|
|
NOTE: The pointer to the ValueString is allocated by this function.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - This is a handle for the registry key that contains the value.
|
|
|
|
ValueName - A pointer to a string that identifies the value being
|
|
obtained.
|
|
|
|
ValueString - A pointer to a location that upon exit will contain the
|
|
pointer to the returned value.
|
|
|
|
Return Value:
|
|
|
|
TRUE - Success
|
|
|
|
FALSE - A fatal error occured.
|
|
|
|
--*/
|
|
{
|
|
DWORD status;
|
|
DWORD maxValueLen;
|
|
TCHAR Temp[1];
|
|
LPTSTR TempValue;
|
|
DWORD ValueType;
|
|
DWORD NumRequired;
|
|
DWORD CharsReturned;
|
|
|
|
//
|
|
// Find the buffer size requirement for the value.
|
|
//
|
|
status = RegQueryValueEx(
|
|
KeyHandle, // hKey
|
|
ValueName, // lpValueName
|
|
NULL, // lpTitleIndex
|
|
&ValueType, // lpType
|
|
NULL, // lpData
|
|
&maxValueLen); // lpcbData
|
|
|
|
if (status != NO_ERROR) {
|
|
MPR_LOG2(ERROR,"MprGetKeyValue:RegQueryValueEx(\"%ws\") failed %d\n",
|
|
ValueName, status);
|
|
*ValueString = NULL;
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Allocate buffer to receive the value string.
|
|
//
|
|
maxValueLen += sizeof(TCHAR);
|
|
|
|
TempValue = (LPTSTR) LocalAlloc(LMEM_FIXED, maxValueLen);
|
|
|
|
if(TempValue == NULL) {
|
|
MPR_LOG(ERROR,"MprGetKeyValue:LocalAlloc failed\n", 0);
|
|
*ValueString = NULL;
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Read the value.
|
|
//
|
|
status = RegQueryValueEx(
|
|
KeyHandle, // hKey
|
|
ValueName, // lpValueName
|
|
NULL, // lpTitleIndex
|
|
&ValueType, // lpType
|
|
(LPBYTE)TempValue, // lpData
|
|
&maxValueLen); // lpcbData
|
|
|
|
if (status != NO_ERROR) {
|
|
MPR_LOG2(ERROR,"MprGetKeyValue:RegQueryValueEx(\"%ws\") failed %d\n",
|
|
ValueName, status);
|
|
LocalFree(TempValue);
|
|
*ValueString = NULL;
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Make sure the value is null-terminated. Strings obtained from
|
|
// the registry may or may not be null-terminated.
|
|
//
|
|
TempValue [ maxValueLen / sizeof(TCHAR) ] = 0;
|
|
|
|
//========================================================
|
|
//
|
|
// If the value is of REG_EXPAND_SZ type, then expand it.
|
|
//
|
|
//========================================================
|
|
|
|
if (ValueType != REG_EXPAND_SZ) {
|
|
*ValueString = TempValue;
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// If the ValueType is REG_EXPAND_SZ, then we must call the
|
|
// function to expand environment variables.
|
|
//
|
|
MPR_LOG(TRACE,"MprGetKeyValue: Must expand the string for "
|
|
FORMAT_LPTSTR "\n", ValueName);
|
|
|
|
//
|
|
// Make the first call just to get the number of characters that
|
|
// will be returned.
|
|
//
|
|
NumRequired = ExpandEnvironmentStrings (TempValue,Temp, 1);
|
|
|
|
if (NumRequired > 1) {
|
|
|
|
*ValueString = (LPTSTR) LocalAlloc(LPTR, (NumRequired+1)*sizeof(TCHAR));
|
|
|
|
if (*ValueString == NULL) {
|
|
|
|
MPR_LOG(ERROR, "MprGetKeyValue: LocalAlloc of numChar= "
|
|
FORMAT_DWORD " failed \n",NumRequired );
|
|
|
|
(void) LocalFree(TempValue);
|
|
return(FALSE);
|
|
}
|
|
|
|
CharsReturned = ExpandEnvironmentStrings (
|
|
TempValue,
|
|
*ValueString,
|
|
NumRequired);
|
|
|
|
(void) LocalFree(TempValue);
|
|
|
|
if (CharsReturned > NumRequired || CharsReturned == 0) {
|
|
MPR_LOG(ERROR, "MprGetKeyValue: ExpandEnvironmentStrings "
|
|
" failed for " FORMAT_LPTSTR " \n", ValueName);
|
|
|
|
(void) LocalFree(*ValueString);
|
|
*ValueString = NULL;
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Now insert the NUL terminator.
|
|
//
|
|
(*ValueString)[CharsReturned] = 0;
|
|
}
|
|
else {
|
|
//
|
|
// This call should have failed because of our ridiculously small
|
|
// buffer size.
|
|
//
|
|
|
|
MPR_LOG(ERROR, "MprGetKeyValue: ExpandEnvironmentStrings "
|
|
" Should have failed because we gave it a BufferSize=1\n",0);
|
|
|
|
//
|
|
// This could happen if the string was a single character long and
|
|
// didn't really have any environment values to expand. In this
|
|
// case, we return the TempValue buffer pointer.
|
|
//
|
|
*ValueString = TempValue;
|
|
}
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
MprGetKeyDwordValue(
|
|
IN HKEY KeyHandle,
|
|
IN LPCWSTR ValueName,
|
|
OUT DWORD * Value
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function takes a key handle and a value name, and returns a DWORD
|
|
value that is associated with that name.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - This is a handle for the registry key that contains the value.
|
|
|
|
ValueName - A pointer to a string that identifies the value being
|
|
obtained. If this value does not have REG_DWORD type the function
|
|
returns FALSE.
|
|
|
|
Value - A pointer to a location that upon exit will contain the returned
|
|
DWORD value.
|
|
|
|
Return Value:
|
|
|
|
TRUE - Success
|
|
|
|
FALSE - A fatal error occured.
|
|
|
|
--*/
|
|
{
|
|
DWORD dwSize = sizeof(DWORD);
|
|
DWORD dwType;
|
|
DWORD status = RegQueryValueEx(
|
|
KeyHandle,
|
|
ValueName,
|
|
0, // reserved
|
|
&dwType, // type
|
|
(LPBYTE) Value,
|
|
&dwSize);
|
|
|
|
if (status)
|
|
{
|
|
MPR_LOG2(ERROR,"MprGetKeyDwordValue: RegQueryValueEx(\"%ws\") failed %ld\n",
|
|
ValueName, status);
|
|
return FALSE;
|
|
}
|
|
else if (dwType != REG_DWORD || dwSize != sizeof(DWORD))
|
|
{
|
|
MPR_LOG3(ERROR,"MprGetKeyDwordValue: RegQueryValueEx(\"%ws\") returned "
|
|
"type %ld, size %ld\n", ValueName, dwType, dwSize);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
LONG
|
|
MprGetKeyNumberValue(
|
|
IN HKEY KeyHandle,
|
|
IN LPCWSTR ValueName,
|
|
IN LONG Default
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function takes a key handle and a value name, and returns a numeric
|
|
value that is associated with that name. If an error occurs while
|
|
retrieving the value, the specified Default value is returned.
|
|
|
|
For compatibility, the behavior of this function is exactly the same as
|
|
Win95's RegEntry::GetNumber function. The value is assumed to be a 4-byte
|
|
type, such as REG_BINARY or REG_DWORD. If this is not the case, the
|
|
function does exactly the same as Win95.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - This is a handle for the registry key that contains the value.
|
|
|
|
ValueName - A pointer to a string that identifies the value being
|
|
obtained.
|
|
|
|
Default - Value to return if one could not be obtained from the registry.
|
|
|
|
Return Value:
|
|
|
|
Value retrieved from the registry, or default if an error occurs.
|
|
|
|
--*/
|
|
{
|
|
LONG dwNumber;
|
|
DWORD dwSize = sizeof(dwNumber);
|
|
|
|
DWORD error = RegQueryValueEx(
|
|
KeyHandle,
|
|
ValueName,
|
|
0, // reserved
|
|
NULL, // type
|
|
(LPBYTE) &dwNumber,
|
|
&dwSize);
|
|
|
|
if (error)
|
|
dwNumber = Default;
|
|
|
|
return dwNumber;
|
|
}
|
|
|
|
|
|
BOOL
|
|
MprGetKeyStringValue(
|
|
IN HKEY KeyHandle,
|
|
IN LPCWSTR ValueName,
|
|
IN DWORD cchMaxValueLength,
|
|
OUT LPWSTR *Value
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function takes a key handle, a value name, and a max size and allocates/returns
|
|
a string value that is associated with that name.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - This is a handle for the registry key that contains the value.
|
|
|
|
ValueName - A pointer to a string that identifies the value being
|
|
obtained. If this value does not have REG_SZ type the function
|
|
returns FALSE.
|
|
|
|
cchMaxValueLength - Size of the OUT buffer to allocate, in characters.
|
|
|
|
Value - A pointer to a location that upon exit will contain the returned
|
|
LPWSTR value.
|
|
|
|
Return Value:
|
|
|
|
TRUE - Success
|
|
|
|
FALSE - A fatal error occured.
|
|
|
|
--*/
|
|
{
|
|
DWORD status;
|
|
DWORD dwType;
|
|
DWORD dwSize = (cchMaxValueLength + 1) * sizeof(WCHAR);
|
|
|
|
*Value = (LPWSTR) LocalAlloc(LMEM_ZEROINIT, dwSize);
|
|
|
|
if (*Value == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
status = RegQueryValueEx(KeyHandle,
|
|
ValueName,
|
|
0, // reserved
|
|
&dwType, // type
|
|
(LPBYTE) *Value,
|
|
&dwSize);
|
|
|
|
if (status || (dwSize % 2) != 0)
|
|
{
|
|
LocalFree(*Value);
|
|
*Value = NULL;
|
|
return FALSE;
|
|
}
|
|
|
|
if (dwType != REG_SZ)
|
|
{
|
|
//
|
|
// Legacy -- MPR writes out a NULL username as a DWORD 0x0. Make sure
|
|
// these values are NULL-terminated
|
|
//
|
|
|
|
(*Value)[cchMaxValueLength] = L'\0';
|
|
return TRUE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
DWORD
|
|
MprEnumKey(
|
|
IN HKEY KeyHandle,
|
|
IN DWORD SubKeyIndex,
|
|
OUT LPTSTR *SubKeyName,
|
|
IN DWORD MaxSubKeyNameLen
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function obtains a single name of a subkey from the registry.
|
|
A key handle for the primary key is passed in. Subkeys are enumerated
|
|
one-per-call with the passed in index indicating where we are in the
|
|
enumeration.
|
|
|
|
NOTE: This function allocates memory for the returned SubKeyName.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - Handle to the key whose sub keys are to be enumerated.
|
|
|
|
SubKeyIndex - Indicates the number (index) of the sub key to be returned.
|
|
|
|
SubKeyName - A pointer to the location where the pointer to the
|
|
subkey name string is to be placed.
|
|
|
|
MaxSubKeyNameLen - This is the length of the largest subkey. This value
|
|
was obtained from calling MprGetKeyInfo. The length is in number
|
|
of characters and does not include the NULL terminator.
|
|
|
|
Return Value:
|
|
|
|
WN_SUCCESS - The operation was successful.
|
|
|
|
STATUS_NO_MORE_SUBKEYS - The SubKeyIndex value was larger than the
|
|
number of subkeys.
|
|
|
|
error returned from LocalAlloc
|
|
|
|
|
|
--*/
|
|
{
|
|
DWORD status;
|
|
FILETIME lastWriteTime;
|
|
DWORD bufferSize;
|
|
|
|
//
|
|
// Allocate buffer to receive the SubKey Name.
|
|
//
|
|
// NOTE: Space is allocated for an extra character because in the case
|
|
// of a drive name, we need to add the trailing colon.
|
|
//
|
|
bufferSize = (MaxSubKeyNameLen + 2) * sizeof(TCHAR);
|
|
*SubKeyName = (LPTSTR) LocalAlloc(LMEM_FIXED, bufferSize);
|
|
|
|
if(*SubKeyName == NULL) {
|
|
MPR_LOG(ERROR,"MprEnumKey:LocalAlloc failed %d\n", GetLastError());
|
|
return(WN_OUT_OF_MEMORY);
|
|
}
|
|
|
|
//
|
|
// Get the Subkey name at that index.
|
|
//
|
|
status = RegEnumKeyEx(
|
|
KeyHandle, // hKey
|
|
SubKeyIndex, // dwIndex
|
|
*SubKeyName, // lpName
|
|
&bufferSize, // lpcbName
|
|
NULL, // lpTitleIndex
|
|
NULL, // lpClass
|
|
NULL, // lpcbClass
|
|
&lastWriteTime); // lpftLastWriteTime
|
|
|
|
if (status != NO_ERROR) {
|
|
MPR_LOG(ERROR,"MprEnumKey:RegEnumKeyEx failed %d\n",status);
|
|
LocalFree(*SubKeyName);
|
|
return(status);
|
|
}
|
|
return(WN_SUCCESS);
|
|
}
|
|
|
|
BOOL
|
|
MprGetKeyInfo(
|
|
IN HKEY KeyHandle,
|
|
OUT LPDWORD TitleIndex OPTIONAL,
|
|
OUT LPDWORD NumSubKeys,
|
|
OUT LPDWORD MaxSubKeyLen,
|
|
OUT LPDWORD NumValues OPTIONAL,
|
|
OUT LPDWORD MaxValueLen
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - Handle to the key for which we are to obtain information.
|
|
|
|
NumSubKeys - This is a pointer to a location where the number
|
|
of sub keys is to be placed.
|
|
|
|
MaxSubKeyLen - This is a pointer to a location where the length of
|
|
the longest subkey name is to be placed.
|
|
|
|
NumValues - This is a pointer to a location where the number of
|
|
key values is to be placed. This pointer is optional and can be
|
|
NULL.
|
|
|
|
MaxValueLen - This is a pointer to a location where the length of
|
|
the longest data value is to be placed.
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE - The operation was successful.
|
|
|
|
FALSE - A failure occured. The returned values are not to be believed.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD status;
|
|
DWORD maxClassLength;
|
|
DWORD numValueNames;
|
|
DWORD maxValueNameLength;
|
|
DWORD securityDescLength;
|
|
FILETIME lastWriteTime;
|
|
|
|
//
|
|
// Get the Key Information
|
|
//
|
|
|
|
status = RegQueryInfoKey(
|
|
KeyHandle,
|
|
NULL, // Class
|
|
NULL, // size of class buffer (in bytes)
|
|
NULL, // DWORD to receive title index
|
|
NumSubKeys, // number of subkeys
|
|
MaxSubKeyLen, // length(chars-no null) of longest subkey name
|
|
&maxClassLength, // length of longest subkey class string
|
|
&numValueNames, // number of valueNames for this key
|
|
&maxValueNameLength, // length of longest ValueName
|
|
MaxValueLen, // length of longest value's data field
|
|
&securityDescLength, // lpcbSecurityDescriptor
|
|
&lastWriteTime); // the last time the key was modified
|
|
|
|
if (status != 0)
|
|
{
|
|
MPR_LOG(ERROR,"MprGetKeyInfo: RegQueryInfoKey Error %d\n",status);
|
|
return(FALSE);
|
|
}
|
|
|
|
if (NumValues != NULL) {
|
|
*NumValues = numValueNames;
|
|
}
|
|
|
|
//
|
|
// Support for title index has been removed from the Registry API.
|
|
//
|
|
if (TitleIndex != NULL) {
|
|
*TitleIndex = 0;
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOL
|
|
MprFindDriveInRegistry (
|
|
IN LPCTSTR DriveName,
|
|
IN OUT LPTSTR *pRemoteName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function determines whether a particular re-directed drive
|
|
name resides in the network connection section of the current user's
|
|
registry path. If the drive is already "remembered" in this section,
|
|
this function returns TRUE.
|
|
|
|
Arguments:
|
|
|
|
DriveName - A pointer to a string containing the name of the redirected
|
|
drive.
|
|
|
|
pRemoteName - If the DriveName is found in the registry, and if this
|
|
is non-null, the remote name for the connection is read, and a
|
|
pointer to the string is stored in this pointer location.
|
|
If the remote name cannot be read from the registry, a NULL
|
|
pointer is returned in this location.
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE - The redirected drive is "remembered in the registry".
|
|
FALSE - The redirected drive is not saved in the registry.
|
|
|
|
--*/
|
|
{
|
|
BOOL bStatus = TRUE;
|
|
HKEY connectKey = NULL;
|
|
HKEY subKey = NULL;
|
|
|
|
LPWSTR KeyName = STACK_ALLOC(DriveName);
|
|
if (KeyName == NULL) {
|
|
return FALSE;
|
|
}
|
|
RemoveColon(KeyName, DriveName);
|
|
|
|
//
|
|
// Get a handle for the connection section of the user's registry
|
|
// space.
|
|
//
|
|
if (!MprOpenKey(
|
|
HKEY_CURRENT_USER,
|
|
CONNECTION_KEY_NAME,
|
|
&connectKey,
|
|
DA_READ)) {
|
|
|
|
MPR_LOG(ERROR,"MprFindDriveInRegistry: MprOpenKey Failed\n",0);
|
|
return (FALSE);
|
|
}
|
|
|
|
if (!MprOpenKey(
|
|
connectKey,
|
|
KeyName,
|
|
&subKey,
|
|
DA_READ)) {
|
|
|
|
MPR_LOG(TRACE,"MprFindDriveInRegistry: Drive %s Not Found\n",DriveName);
|
|
bStatus = FALSE;
|
|
}
|
|
else {
|
|
//
|
|
// The drive was found in the registry, if the caller wants to have
|
|
// the RemoteName, then get it.
|
|
//
|
|
if (pRemoteName != NULL) {
|
|
|
|
//
|
|
// Get the RemoteName (memory is allocated by this function)
|
|
//
|
|
|
|
if(!MprGetKeyValue(
|
|
subKey,
|
|
REMOTE_PATH_NAME,
|
|
pRemoteName)) {
|
|
|
|
MPR_LOG(TRACE,"MprFindDriveInRegistry: Could not read "
|
|
"Remote path for Drive %ws \n",DriveName);
|
|
pRemoteName = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( subKey )
|
|
RegCloseKey(subKey);
|
|
if ( connectKey )
|
|
RegCloseKey(connectKey);
|
|
|
|
return(bStatus);
|
|
}
|
|
|
|
|
|
DWORD
|
|
I_MprSaveConn(
|
|
IN HKEY HiveRoot,
|
|
IN LPCWSTR ProviderName,
|
|
IN DWORD ProviderType,
|
|
IN LPCWSTR UserName,
|
|
IN LPCWSTR LocalName,
|
|
IN LPCWSTR RemoteName,
|
|
IN DWORD ConnectionType,
|
|
IN BYTE ProviderFlags,
|
|
IN DWORD DeferFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Writes the information about a connection to the network connection
|
|
section of a user's registry path.
|
|
|
|
NOTE: If connection information is already stored in the registry for
|
|
this drive, the current information will be overwritten with the new
|
|
information.
|
|
|
|
Arguments:
|
|
|
|
HiveRoot - A handle to the root of the user hive in which this
|
|
information should be written, such as HKEY_CURRENT_USER.
|
|
|
|
ProviderName - The provider that completed the connection.
|
|
|
|
ProviderType - The provider type, if known. If not known, zero should
|
|
be passed, and a type will not be written to the registry. (This
|
|
is used by setup when upgrading from Win95 to NT.)
|
|
|
|
UserName - The name of the user on whose behalf the connection was made.
|
|
|
|
LocalName - The name of the local device that is redirected, with or
|
|
without a trailing colon, such as "J" or "J:" or "LPT1".
|
|
|
|
RemoteName - The network path to which the connection was made.
|
|
|
|
ConnectionType - either RESOURCETYPE_DISK or RESOURCETYPE_PRINT.
|
|
|
|
ProviderFlags - A byte of data to be saved along with the connection,
|
|
and passed back to the provider when the connection is restored.
|
|
|
|
DeferFlags - A DWORD to be saved in the connection's "Defer" value. If
|
|
this is zero, the value is not stored.
|
|
The meaning of the bits of this DWORD are as follows:
|
|
DEFER_EXPLICIT_PASSWORD - a password was explicitly specified when
|
|
the connection was made.
|
|
DEFER_UNKNOWN - it is not known whether a password was explicitly
|
|
specified when the connection was made.
|
|
DEFER_DEFAULT_CRED - The provider believes that default creds were
|
|
used when the connection was made.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS - If the operation was successful.
|
|
|
|
Other Win32 errors - If the operation failed in any way. If a failure
|
|
occurs, the information is not stored in the registry.
|
|
|
|
--*/
|
|
{
|
|
HKEY connectKey;
|
|
HKEY localDevHandle;
|
|
LPCTSTR pUserName;
|
|
DWORD status, IgnoredStatus;
|
|
|
|
//
|
|
// Remove the colon on the name since the registry doesn't like
|
|
// this in a key name.
|
|
//
|
|
LPWSTR KeyName = STACK_ALLOC(LocalName);
|
|
if (KeyName == NULL) {
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
RemoveColon(KeyName, LocalName);
|
|
|
|
//
|
|
// Get a handle for the connection section of the user's registry
|
|
// space.
|
|
//
|
|
if ((status = MprCreateRegKey(
|
|
HiveRoot,
|
|
CONNECTION_KEY_NAME,
|
|
&connectKey)) != ERROR_SUCCESS) {
|
|
|
|
MPR_LOG(ERROR,"I_MprSaveConn: \\HKEY_CURRENT_USER\\network "
|
|
"could not be opened or created, error %ld\n", status);
|
|
return(status);
|
|
}
|
|
|
|
//
|
|
// Get (or create) the handle for the local name (without colon).
|
|
//
|
|
if ((status = MprCreateRegKey(
|
|
connectKey,
|
|
KeyName,
|
|
&localDevHandle)) != ERROR_SUCCESS) {
|
|
|
|
MPR_LOG(ERROR,"I_MprSaveConn: MprCreateRegKey Failed, "
|
|
"error %ld\n", status);
|
|
RegCloseKey(connectKey);
|
|
return(status);
|
|
}
|
|
|
|
|
|
//
|
|
// Now that the key is created, store away the appropriate values.
|
|
//
|
|
|
|
MPR_LOG(TRACE,"RememberConnection: Setting RemotePath\n",0);
|
|
|
|
if((status = MprSetRegValue(
|
|
localDevHandle,
|
|
REMOTE_PATH_NAME,
|
|
RemoteName,
|
|
0)) != ERROR_SUCCESS) {
|
|
|
|
MPR_LOG(ERROR,
|
|
"I_MprSaveConn: MprSetRegValueFailed %lu - RemotePath\n",status);
|
|
goto CleanExit;
|
|
}
|
|
|
|
MPR_LOG(TRACE,"RememberConnection: Setting User\n",0);
|
|
|
|
pUserName = UserName;
|
|
if (UserName == NULL) {
|
|
pUserName = TEXT("");
|
|
}
|
|
if((status = MprSetRegValue(
|
|
localDevHandle,
|
|
USER_NAME,
|
|
pUserName,
|
|
0)) != ERROR_SUCCESS) {
|
|
|
|
goto CleanExit;
|
|
}
|
|
|
|
MPR_LOG(TRACE,"RememberConnection: Setting ProviderName\n",0);
|
|
if((status = MprSetRegValue(
|
|
localDevHandle,
|
|
PROVIDER_NAME,
|
|
ProviderName,
|
|
0)) != ERROR_SUCCESS) {
|
|
|
|
goto CleanExit;
|
|
}
|
|
|
|
if (ProviderType != 0)
|
|
{
|
|
MPR_LOG(TRACE,"RememberConnection: Setting ProviderType\n",0);
|
|
if((status = MprSetRegValue(
|
|
localDevHandle,
|
|
PROVIDER_TYPE,
|
|
NULL,
|
|
ProviderType)) != ERROR_SUCCESS) {
|
|
|
|
goto CleanExit;
|
|
}
|
|
}
|
|
// else RegDeleteValue -- not done because ProviderType is 0 only
|
|
// during upgrade, while writing to a fresh user hive
|
|
|
|
MPR_LOG(TRACE,"RememberConnection: Setting ConnectionType\n",0);
|
|
if((status = MprSetRegValue(
|
|
localDevHandle,
|
|
CONNECTION_TYPE,
|
|
NULL,
|
|
ConnectionType)) != ERROR_SUCCESS) {
|
|
|
|
goto CleanExit;
|
|
}
|
|
|
|
if (ProviderFlags != 0)
|
|
{
|
|
MPR_LOG(TRACE,"RememberConnection: Setting ProviderFlags\n",0);
|
|
if((status = MprSetRegValue(
|
|
localDevHandle,
|
|
PROVIDER_FLAGS,
|
|
NULL,
|
|
ProviderFlags)) != ERROR_SUCCESS) {
|
|
|
|
goto CleanExit;
|
|
}
|
|
}
|
|
|
|
// We can't roll this back if something fails after it, so we
|
|
// must do this last
|
|
if ((status = MprSaveDeferFlags(localDevHandle, DeferFlags))
|
|
!= ERROR_SUCCESS) {
|
|
|
|
goto CleanExit;
|
|
}
|
|
|
|
//
|
|
// Flush the new key, and then close the handle to it.
|
|
//
|
|
|
|
MPR_LOG(TRACE,"RememberConnection: Flushing Registry Key\n",0);
|
|
|
|
IgnoredStatus = RegFlushKey(localDevHandle);
|
|
if (IgnoredStatus != NO_ERROR) {
|
|
MPR_LOG(ERROR,"RememberConnection: Flushing Registry Key Failed %ld\n",
|
|
IgnoredStatus);
|
|
}
|
|
|
|
CleanExit:
|
|
RegCloseKey(localDevHandle);
|
|
if (status != ERROR_SUCCESS) {
|
|
IgnoredStatus = RegDeleteKey(connectKey, KeyName);
|
|
if (IgnoredStatus != NO_ERROR) {
|
|
MPR_LOG(ERROR, "RememberConnection: RegDeleteKey Failed %d\n", IgnoredStatus);
|
|
}
|
|
}
|
|
RegCloseKey(connectKey);
|
|
return(status);
|
|
|
|
}
|
|
|
|
|
|
DWORD
|
|
MprSaveDeferFlags(
|
|
IN HKEY RegKey,
|
|
IN DWORD DeferFlags
|
|
)
|
|
{
|
|
DWORD status;
|
|
|
|
if (DeferFlags == 0)
|
|
{
|
|
MPR_LOG0(TRACE,"Removing DeferFlags\n");
|
|
status = RegDeleteValue(RegKey, DEFER_FLAGS);
|
|
if (status == ERROR_FILE_NOT_FOUND)
|
|
{
|
|
status = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MPR_LOG(TRACE,"Setting DeferFlags %#lx\n",DeferFlags);
|
|
status = MprSetRegValue(
|
|
RegKey,
|
|
DEFER_FLAGS,
|
|
NULL,
|
|
DeferFlags);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
DWORD
|
|
MprSetRegValue(
|
|
IN HKEY KeyHandle,
|
|
IN LPTSTR ValueName,
|
|
IN LPCTSTR ValueString,
|
|
IN DWORD LongValue
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Stores a single ValueName and associated data in the registry for
|
|
the key identified by the KeyHandle. The data associated with the
|
|
value can either be a string or a 32-bit LONG. If the ValueString
|
|
argument contains a pointer to a value, then the LongValue argument
|
|
is ignored.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - Handle of the key for which the value entry is to be set.
|
|
|
|
ValueName - Pointer to a string that contains the name of the value
|
|
being set.
|
|
|
|
ValueString - Pointer to a string that is to become the data stored
|
|
at that value name. If this argument is not present, then the
|
|
LongValue argument is the data stored at the value name. If this
|
|
argument is present, then LongValue is ignored.
|
|
|
|
LongValue - A LONG sized data value that is to be stored at the
|
|
value name.
|
|
|
|
Return Value:
|
|
|
|
Win32 error from RegSetValueEx (0 = success)
|
|
|
|
--*/
|
|
{
|
|
DWORD status;
|
|
const BYTE * valueData;
|
|
DWORD valueSize;
|
|
DWORD valueType;
|
|
|
|
if( ARGUMENT_PRESENT(ValueString)) {
|
|
valueData = (const BYTE *)ValueString;
|
|
valueSize = (wcslen(ValueString) + 1) * sizeof(WCHAR);
|
|
valueType = REG_SZ;
|
|
}
|
|
else {
|
|
valueData = (const BYTE *)&LongValue;
|
|
valueSize = sizeof(DWORD);
|
|
valueType = REG_DWORD;
|
|
}
|
|
status = RegSetValueEx(
|
|
KeyHandle, // hKey
|
|
ValueName, // lpValueName
|
|
0, // dwValueTitle (OPTIONAL)
|
|
valueType, // dwType
|
|
valueData, // lpData
|
|
valueSize); // cbData
|
|
|
|
if(status != NO_ERROR) {
|
|
MPR_LOG3(ERROR,"MprSetRegValue: RegSetValueEx(%#lx \"%ws\") Failed %ld\n",
|
|
KeyHandle, ValueName, status);
|
|
}
|
|
return(status);
|
|
}
|
|
|
|
|
|
DWORD
|
|
MprCreateRegKey(
|
|
IN HKEY BaseKeyHandle,
|
|
IN LPCTSTR KeyName,
|
|
OUT PHKEY KeyHandlePtr
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a key in the registry at the location described by KeyName.
|
|
|
|
Arguments:
|
|
|
|
BaseKeyHandle - This is a handle for the base (parent) key - where the
|
|
subkey is to be created.
|
|
|
|
KeyName - This is a pointer to a string that describes the path to the
|
|
key that is to be created.
|
|
|
|
KeyHandle - This is a pointer to a location where the the handle for the
|
|
newly created key is to be placed.
|
|
|
|
Return Value:
|
|
|
|
Win32 error from RegCreateKeyEx (0 = success)
|
|
|
|
Note:
|
|
|
|
|
|
--*/
|
|
{
|
|
DWORD status;
|
|
DWORD disposition;
|
|
|
|
|
|
//
|
|
// Create the new key.
|
|
//
|
|
status = RegCreateKeyEx(
|
|
BaseKeyHandle, // hKey
|
|
KeyName, // lpSubKey
|
|
0L, // dwTitleIndex
|
|
TEXT("GenericClass"), // lpClass
|
|
0, // ulOptions
|
|
KEY_WRITE, // samDesired (desired access)
|
|
NULL, // lpSecurityAttrubutes (Security Descriptor)
|
|
KeyHandlePtr, // phkResult
|
|
&disposition); // lpulDisposition
|
|
|
|
if (status != NO_ERROR) {
|
|
MPR_LOG3(ERROR,"MprCreateRegKey: RegCreateKeyEx(%#lx, \"%ws\") failed %d\n",
|
|
BaseKeyHandle, KeyName, status);
|
|
}
|
|
else {
|
|
MPR_LOG(TRACE,"MprCreateRegKey: Disposition = 0x%x\n",disposition);
|
|
}
|
|
return(status);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
MprReadConnectionInfo(
|
|
IN HKEY KeyHandle,
|
|
IN LPCTSTR DriveName,
|
|
IN DWORD Index,
|
|
OUT LPDWORD ProviderFlags,
|
|
OUT LPDWORD DeferFlags,
|
|
OUT LPTSTR *UserNamePtr,
|
|
OUT LPNETRESOURCEW NetResource,
|
|
OUT HKEY *SubKeyHandleOut,
|
|
IN DWORD MaxSubKeyLen
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function reads the data associated with a connection key.
|
|
Buffers are allocated to store:
|
|
|
|
UserName, RemoteName, LocalName, Provider
|
|
|
|
Pointers to those buffers are returned.
|
|
|
|
Also the connection type is read and stored in the NetResource structure.
|
|
|
|
If the provider type is found in the registry, and a matching provider
|
|
type is found in the GlobalProviderInfo array, the provider name is not
|
|
read from the registry. Instead it is read from the GlobalProviderInfo
|
|
array.
|
|
|
|
If the provider name is read from the registry and a matching provider
|
|
name is found in the GlobalProviderInfo array, the provider type is
|
|
written to the registry.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - This is an already opened handle to the key whose
|
|
sub-keys are to be enumerated.
|
|
|
|
DriveName - This is the local name of the drive (eg. "f:") for which
|
|
the connection information is to be obtained. If DriveName is
|
|
NULL, then the Index is used to enumerate the keyname. Then
|
|
that keyname is used.
|
|
|
|
Index - This is the index that identifies the subkey for which we
|
|
would like to receive information.
|
|
|
|
ProviderFlags - This is a pointer to a location where the ProviderFlags
|
|
value stored with the connection will be placed. If this value
|
|
cannot be retrieved, 0 will be placed here.
|
|
|
|
DeferFlags - This is a pointer to a location where the DeferFlags
|
|
value stored with the connection will be placed. If this value
|
|
cannot be retrieved, 0 will be placed here.
|
|
|
|
UserNamePtr - This is a pointer to a location where the pointer to the
|
|
UserName string is to be placed. If there is no user name, a
|
|
NULL pointer will be returned.
|
|
|
|
NetResource - This is a pointer to a NETRESOURCE structure where
|
|
information such as lpRemoteName, lpLocalName, lpProvider, and Type
|
|
are to be placed.
|
|
|
|
SubKeyHandleOut - This is a pointer to a location where the handle to
|
|
the subkey that holds information about this connection will be
|
|
placed. This may be NULL. If it is not NULL the caller must close
|
|
the handle.
|
|
|
|
Return Value:
|
|
|
|
|
|
|
|
Note:
|
|
|
|
|
|
--*/
|
|
{
|
|
DWORD status = NO_ERROR;
|
|
LPTSTR driveName = NULL;
|
|
HKEY subKeyHandle = NULL;
|
|
DWORD cbData;
|
|
DWORD ProviderType = 0;
|
|
LPPROVIDER Provider;
|
|
|
|
//
|
|
// Initialize the Pointers that are to be updated.
|
|
//
|
|
*UserNamePtr = NULL;
|
|
NetResource->lpLocalName = NULL;
|
|
NetResource->lpRemoteName = NULL;
|
|
NetResource->lpProvider = NULL;
|
|
NetResource->dwType = 0L;
|
|
|
|
//
|
|
// If we don't have a DriveName, then get one by enumerating the
|
|
// next key name.
|
|
//
|
|
|
|
if (DriveName == NULL) {
|
|
//
|
|
// Get the name of a subkey of the network connection key.
|
|
// (memory is allocated by this function).
|
|
//
|
|
status = MprEnumKey(KeyHandle, Index, &driveName, MaxSubKeyLen);
|
|
if (status != WN_SUCCESS) {
|
|
return(FALSE);
|
|
}
|
|
}
|
|
else {
|
|
//
|
|
// We have a drive name, alloc new space and copy it to that
|
|
// location.
|
|
//
|
|
driveName = (LPTSTR) LocalAlloc(LMEM_FIXED, (wcslen(DriveName) + 1) * sizeof(WCHAR));
|
|
if (driveName == NULL) {
|
|
MPR_LOG(ERROR, "MprReadConnectionInfo: Local Alloc Failed %d\n",
|
|
GetLastError());
|
|
return(FALSE);
|
|
}
|
|
|
|
RemoveColon(driveName, DriveName);
|
|
}
|
|
|
|
MPR_LOG1(TRACE,"MprReadConnectionInfo: LocalName = %ws\n",driveName);
|
|
|
|
//
|
|
// Open the sub-key
|
|
//
|
|
if (!MprOpenKey(
|
|
KeyHandle,
|
|
driveName,
|
|
&subKeyHandle,
|
|
DA_WRITE)){
|
|
|
|
status = WN_BAD_PROFILE;
|
|
MPR_LOG1(TRACE,"MprReadConnectionInfo: Could not open %ws Key\n",driveName);
|
|
goto CleanExit;
|
|
}
|
|
|
|
//
|
|
// Add the trailing colon to the driveName.
|
|
//
|
|
cbData = wcslen(driveName);
|
|
driveName[cbData] = TEXT(':');
|
|
driveName[cbData+1] = TEXT('\0');
|
|
|
|
//
|
|
// Store the drive name in the return structure.
|
|
//
|
|
NetResource->lpLocalName = driveName;
|
|
|
|
//
|
|
// Get the RemoteName (memory is allocated by this function)
|
|
//
|
|
|
|
if(!MprGetKeyValue(
|
|
subKeyHandle,
|
|
REMOTE_PATH_NAME,
|
|
&(NetResource->lpRemoteName))) {
|
|
|
|
status = WN_BAD_PROFILE;
|
|
MPR_LOG0(TRACE,"MprReadConnectionInfo: Could not get RemoteName\n");
|
|
goto CleanExit;
|
|
}
|
|
|
|
//
|
|
// Get the UserName (memory is allocated by this function)
|
|
//
|
|
|
|
if(!MprGetKeyStringValue(
|
|
subKeyHandle,
|
|
USER_NAME,
|
|
CRED_MAX_USERNAME_LENGTH,
|
|
UserNamePtr))
|
|
{
|
|
status = WN_BAD_PROFILE;
|
|
MPR_LOG0(TRACE,"MprReadConnectionInfo: Could not get UserName\n");
|
|
goto CleanExit;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If there is no user name (the length is 0), then set the
|
|
// return pointer to NULL.
|
|
//
|
|
if (wcslen(*UserNamePtr) == 0) {
|
|
LocalFree(*UserNamePtr);
|
|
*UserNamePtr = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get the Provider Type and load the providers if necessary. Both
|
|
// MprGetConnection and a remembered enumeration can make it to this
|
|
// point in this state and we don't want to do a Level 2
|
|
// initialization every time one of those functions is called simply
|
|
// because this case _might_ be hit. For example, calling
|
|
// MprGetConnection on an unconnected drive letter may or may not
|
|
// have a name associated with it in the registry. If so, there's
|
|
// no need to load the providers to get information from them. This
|
|
// is equivalent to INIT_IF_NECESSARY(NETWORK_LEVEL,status)
|
|
//
|
|
if (MprGetKeyDwordValue(
|
|
subKeyHandle,
|
|
PROVIDER_TYPE,
|
|
&ProviderType)
|
|
&&
|
|
(MprLevel2Init(NETWORK_LEVEL) == WN_SUCCESS)
|
|
&&
|
|
((Provider = MprFindProviderByType(ProviderType)) != NULL))
|
|
{
|
|
MPR_LOG(RESTORE,"MprReadConnectionInfo: Found recognized provider type %#lx\n",
|
|
ProviderType);
|
|
//
|
|
// Got a recognized provider type from the registry.
|
|
// If we have a name for this provider in memory, use it, rather than
|
|
// reading the name from the registry.
|
|
// (memory is allocated for the name)
|
|
//
|
|
if (Provider->Resource.lpProvider != NULL)
|
|
{
|
|
NetResource->lpProvider =
|
|
(LPWSTR) LocalAlloc(0, (wcslen(Provider->Resource.lpProvider) + 1) * sizeof(WCHAR));
|
|
|
|
if (NetResource->lpProvider == NULL)
|
|
{
|
|
status = WN_BAD_PROFILE;
|
|
MPR_LOG(RESTORE,"MprReadConnectionInfo: LocalAlloc failed %ld\n",
|
|
GetLastError());
|
|
goto CleanExit;
|
|
}
|
|
|
|
wcscpy(NetResource->lpProvider, Provider->Resource.lpProvider);
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we haven't got a provider name yet, try to read it from the registry.
|
|
// (Memory is allocated by this function.)
|
|
// This could legitimately happen in 2 cases:
|
|
// (1) We are reading a profile that was created by a Windows NT 3.51 or
|
|
// earlier machine and has not yet been converted to a 4.0 or later
|
|
// profile. Windows NT versions 3.51 and earlier wrote only the provider
|
|
// name to the registry, not the type.
|
|
// (2) We are reading a floating profile that was written by another
|
|
// machine which has a network provider installed that isn't installed on
|
|
// this machine. Or, a network provider was de-installed from this
|
|
// machine.
|
|
//
|
|
if (NetResource->lpProvider == NULL)
|
|
{
|
|
if(!MprGetKeyValue(
|
|
subKeyHandle,
|
|
PROVIDER_NAME,
|
|
&(NetResource->lpProvider)))
|
|
{
|
|
status = WN_BAD_PROFILE;
|
|
MPR_LOG0(RESTORE,"MprReadConnectionInfo: Could not get ProviderName\n");
|
|
goto CleanExit;
|
|
}
|
|
|
|
//
|
|
// Got a provider name from the registry.
|
|
// If we didn't read a provider type from the registry, but we
|
|
// recognize the provider name, write the type now for future use.
|
|
// (This would occur in case (1) above.)
|
|
// Failure to write the type is ignored.
|
|
// (Pathological cases in which we get an unrecognized type but a
|
|
// recognized name are left untouched.)
|
|
// Since it's possible to get to this point without having the
|
|
// providers loaded, we'll init if necessary here (see reasoning
|
|
// above). This is equivalent to INIT_IF_NECESSARY(NETWORK_LEVEL,status)
|
|
//
|
|
status = MprLevel2Init(NETWORK_LEVEL);
|
|
|
|
if (status != WN_SUCCESS) {
|
|
goto CleanExit;
|
|
}
|
|
|
|
Provider = MprFindProviderByName(NetResource->lpProvider);
|
|
if (Provider != NULL && Provider->Type != 0 && ProviderType == 0)
|
|
{
|
|
MPR_LOG2(RESTORE,"MprReadConnectionInfo: Setting ProviderType %#lx for %ws\n",
|
|
Provider->Type, driveName);
|
|
|
|
status = MprSetRegValue(
|
|
subKeyHandle,
|
|
PROVIDER_TYPE,
|
|
NULL,
|
|
Provider->Type);
|
|
|
|
if (status != ERROR_SUCCESS)
|
|
{
|
|
MPR_LOG(RESTORE,"MprReadConnectionInfo: Couldn't set ProviderType, %ld\n",
|
|
status);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Get the ProviderFlags (failure is ignored)
|
|
//
|
|
cbData = sizeof(DWORD);
|
|
|
|
status = RegQueryValueEx(
|
|
subKeyHandle, // hKey
|
|
PROVIDER_FLAGS, // lpValueName
|
|
NULL, // lpTitleIndex
|
|
NULL, // lpType
|
|
(LPBYTE)ProviderFlags, // lpData
|
|
&cbData); // lpcbData
|
|
|
|
if (status == NO_ERROR) {
|
|
MPR_LOG2(RESTORE,"MprReadConnectionInfo: Got ProviderFlags %#lx for %ws\n",
|
|
*ProviderFlags, driveName);
|
|
}
|
|
else {
|
|
*ProviderFlags = 0;
|
|
}
|
|
|
|
|
|
//
|
|
// Get the DeferFlags (failure is ignored)
|
|
//
|
|
if (MprGetKeyDwordValue(
|
|
subKeyHandle,
|
|
DEFER_FLAGS,
|
|
DeferFlags
|
|
))
|
|
{
|
|
MPR_LOG2(RESTORE,"MprReadConnectionInfo: Got DeferFlags %#lx for %ws\n",
|
|
*DeferFlags, driveName);
|
|
}
|
|
else
|
|
{
|
|
*DeferFlags = 0;
|
|
}
|
|
|
|
|
|
//
|
|
// Get the Connection Type
|
|
//
|
|
cbData = sizeof(DWORD);
|
|
|
|
status = RegQueryValueEx(
|
|
subKeyHandle, // hKey
|
|
CONNECTION_TYPE, // lpValueName
|
|
NULL, // lpTitleIndex
|
|
NULL, // lpType
|
|
(LPBYTE)&(NetResource->dwType), // lpData
|
|
&cbData); // lpcbData
|
|
|
|
if (status != NO_ERROR) {
|
|
MPR_LOG1(ERROR,"MprReadConnectionInfo:RegQueryValueEx failed %d\n",
|
|
status);
|
|
|
|
MPR_LOG0(TRACE,"MprReadConnectionInfo: Could not get ConnectionType\n");
|
|
status = WN_BAD_PROFILE;
|
|
}
|
|
|
|
|
|
CleanExit:
|
|
if (status != NO_ERROR) {
|
|
LocalFree(driveName);
|
|
LocalFree(NetResource->lpRemoteName);
|
|
LocalFree(*UserNamePtr);
|
|
LocalFree(NetResource->lpProvider);
|
|
NetResource->lpLocalName = NULL;
|
|
NetResource->lpRemoteName = NULL;
|
|
NetResource->lpProvider = NULL;
|
|
*UserNamePtr = NULL;
|
|
if (subKeyHandle != NULL) {
|
|
RegCloseKey(subKeyHandle);
|
|
}
|
|
return(FALSE);
|
|
}
|
|
else {
|
|
if (SubKeyHandleOut == NULL) {
|
|
RegCloseKey(subKeyHandle);
|
|
}
|
|
else {
|
|
*SubKeyHandleOut = subKeyHandle;
|
|
}
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
MprForgetRedirConnection(
|
|
IN LPCTSTR lpName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function removes a key for the specified redirected device from
|
|
the current users portion of the registry.
|
|
|
|
Arguments:
|
|
|
|
lpName - This is a pointer to a redirected device name.
|
|
|
|
Return Value:
|
|
|
|
|
|
Note:
|
|
|
|
|
|
--*/
|
|
{
|
|
DWORD status;
|
|
HKEY connectKey;
|
|
|
|
MPR_LOG(TRACE,"In MprForgetConnection for %s\n", lpName);
|
|
|
|
LPWSTR KeyName = STACK_ALLOC(lpName);
|
|
if (KeyName == NULL) {
|
|
return;
|
|
}
|
|
RemoveColon(KeyName, lpName);
|
|
|
|
//
|
|
// Get a handle for the connection section of the user's registry
|
|
// space.
|
|
//
|
|
if (!MprOpenKey(
|
|
HKEY_CURRENT_USER,
|
|
CONNECTION_KEY_NAME,
|
|
&connectKey,
|
|
DA_READ)) {
|
|
|
|
MPR_LOG(ERROR,"WNetForgetRedirCon: MprOpenKey #1 Failed\n",0);
|
|
return;
|
|
}
|
|
|
|
status = RegDeleteKey(connectKey, KeyName);
|
|
|
|
if (status != NO_ERROR) {
|
|
MPR_LOG(ERROR, "WNetForgetRedirCon: NtDeleteKey Failed %d\n", status);
|
|
}
|
|
|
|
//
|
|
// Flush the connect key, and then close the handle to it.
|
|
//
|
|
|
|
MPR_LOG(TRACE,"ForgetRedirConnection: Flushing Connection Key\n",0);
|
|
|
|
status = RegFlushKey(connectKey);
|
|
if (status != NO_ERROR) {
|
|
MPR_LOG(ERROR,"RememberConnection: Flushing Connection Key Failed %ld\n",
|
|
status);
|
|
}
|
|
|
|
RegCloseKey(connectKey);
|
|
|
|
return;
|
|
}
|
|
BOOL
|
|
MprGetRemoteName(
|
|
IN LPTSTR lpLocalName,
|
|
IN OUT LPDWORD lpBufferSize,
|
|
OUT LPTSTR lpRemoteName,
|
|
OUT LPDWORD lpStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This fuction Looks in the CURRENT_USER portion of the registry for
|
|
connection information related to the lpLocalName passed in.
|
|
|
|
Arguments:
|
|
|
|
lpLocalName - Pointer to a string containing the name of the device to
|
|
look up.
|
|
|
|
lpBufferSize - Pointer to a the size information for the buffer.
|
|
On input, this contains the size of the buffer passed in.
|
|
if lpStatus contain WN_MORE_DATA, this will contain the
|
|
buffer size required to obtain the full string.
|
|
|
|
lpRemoteName - Pointer to a buffer where the remote name string is
|
|
to be placed.
|
|
|
|
lpStatus - Pointer to a location where the proper return code is to
|
|
be placed in the case where the connection information exists.
|
|
|
|
Return Value:
|
|
|
|
TRUE - If the connection information exists.
|
|
|
|
FALSE - If the connection information does not exist. When FALSE is
|
|
returned, none of output parameters are valid.
|
|
|
|
--*/
|
|
{
|
|
HKEY connectKey;
|
|
DWORD numSubKeys;
|
|
DWORD maxSubKeyLen;
|
|
DWORD maxValueLen;
|
|
DWORD status;
|
|
DWORD ProviderFlags;
|
|
DWORD DeferFlags;
|
|
NETRESOURCEW netResource;
|
|
LPTSTR userName;
|
|
|
|
|
|
//
|
|
// Get a handle for the connection section of the user's registry
|
|
// space.
|
|
//
|
|
if (!MprOpenKey(
|
|
HKEY_CURRENT_USER,
|
|
CONNECTION_KEY_NAME,
|
|
&connectKey,
|
|
DA_READ)) {
|
|
|
|
MPR_LOG(ERROR,"WNetGetConnection: MprOpenKey Failed\n",0);
|
|
return(FALSE);
|
|
}
|
|
|
|
if(!MprGetKeyInfo(
|
|
connectKey,
|
|
NULL,
|
|
&numSubKeys,
|
|
&maxSubKeyLen,
|
|
NULL,
|
|
&maxValueLen)) {
|
|
|
|
MPR_LOG(ERROR,"WNetGetConnection: MprGetKeyInfo Failed\n",0);
|
|
RegCloseKey(connectKey);
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Read the connection information.
|
|
// NOTE: This function allocates buffers for UserName and the
|
|
// following strings in the net resource structure:
|
|
// lpRemoteName,
|
|
// lpLocalName,
|
|
// lpProvider
|
|
//
|
|
if (MprReadConnectionInfo(
|
|
connectKey,
|
|
lpLocalName,
|
|
0,
|
|
&ProviderFlags,
|
|
&DeferFlags,
|
|
&userName,
|
|
&netResource,
|
|
NULL,
|
|
maxSubKeyLen)) {
|
|
|
|
//
|
|
// The read succeeded. Therefore we have connection information.
|
|
//
|
|
|
|
if (*lpBufferSize >= (wcslen(netResource.lpRemoteName) + 1) * sizeof(WCHAR)) {
|
|
|
|
__try {
|
|
wcscpy(lpRemoteName, netResource.lpRemoteName);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER) {
|
|
status = GetExceptionCode();
|
|
if (status != EXCEPTION_ACCESS_VIOLATION) {
|
|
MPR_LOG(ERROR,"WNetGetConnection:Unexpected Exception 0x%lx\n",status);
|
|
}
|
|
status = WN_BAD_POINTER;
|
|
}
|
|
if (status != WN_BAD_POINTER) {
|
|
|
|
//
|
|
// We successfully copied the remote name to the users
|
|
// buffer without an error.
|
|
//
|
|
status = WN_SUCCESS;
|
|
}
|
|
}
|
|
else {
|
|
*lpBufferSize = (wcslen(netResource.lpRemoteName) + 1) * sizeof(WCHAR);
|
|
status = WN_MORE_DATA;
|
|
}
|
|
|
|
//
|
|
// Free up the resources allocated by MprReadConnectionInfo.
|
|
//
|
|
|
|
LocalFree(userName);
|
|
LocalFree(netResource.lpLocalName);
|
|
LocalFree(netResource.lpRemoteName);
|
|
LocalFree(netResource.lpProvider);
|
|
|
|
*lpStatus = status;
|
|
RegCloseKey(connectKey);
|
|
return(TRUE);
|
|
}
|
|
else {
|
|
//
|
|
// The read did not succeed.
|
|
//
|
|
RegCloseKey(connectKey);
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
DWORD
|
|
MprGetPrintKeyInfo(
|
|
HKEY KeyHandle,
|
|
LPDWORD NumValueNames,
|
|
LPDWORD MaxValueNameLength,
|
|
LPDWORD MaxValueLen)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function reads the data associated with a print reconnection key.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - This is an already opened handle to the key whose
|
|
info is rto be queried.
|
|
|
|
NumValueNames - Used to return the number of values
|
|
|
|
MaxValueNameLength - Used to return the max value name length
|
|
|
|
MaxValueLen - Used to return the max value data length
|
|
|
|
Return Value:
|
|
|
|
0 if success. Win32 error otherwise.
|
|
|
|
|
|
Note:
|
|
|
|
--*/
|
|
{
|
|
DWORD err;
|
|
DWORD maxClassLength;
|
|
DWORD securityDescLength;
|
|
DWORD NumSubKeys ;
|
|
DWORD MaxSubKeyLen ;
|
|
FILETIME lastWriteTime;
|
|
|
|
//
|
|
// Get the Key Information
|
|
//
|
|
|
|
err = RegQueryInfoKey(
|
|
KeyHandle,
|
|
NULL, // Class
|
|
NULL, // size of class buffer (in bytes)
|
|
NULL, // DWORD to receive title index
|
|
&NumSubKeys, // number of subkeys
|
|
&MaxSubKeyLen, // length of longest subkey name
|
|
&maxClassLength, // length of longest subkey class string
|
|
NumValueNames, // number of valueNames for this key
|
|
MaxValueNameLength, // length of longest ValueName
|
|
MaxValueLen, // length of longest value's data field
|
|
&securityDescLength, // lpcbSecurityDescriptor
|
|
&lastWriteTime); // the last time the key was modified
|
|
|
|
return(err);
|
|
}
|
|
|
|
DWORD
|
|
MprForgetPrintConnection(
|
|
IN LPTSTR lpName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function removes a rememembered print reconnection value.
|
|
|
|
Arguments:
|
|
|
|
lpName - name of path to forget
|
|
|
|
Return Value:
|
|
|
|
0 if success. Win32 error otherwise.
|
|
|
|
|
|
Note:
|
|
|
|
--*/
|
|
{
|
|
HKEY hKey ;
|
|
DWORD err ;
|
|
|
|
if (!MprOpenKey(
|
|
HKEY_CURRENT_USER,
|
|
PRINT_CONNECTION_KEY_NAME,
|
|
&hKey,
|
|
DA_WRITE))
|
|
{
|
|
return (GetLastError()) ;
|
|
}
|
|
|
|
err = RegDeleteValue(hKey,
|
|
lpName) ;
|
|
|
|
RegCloseKey(hKey) ;
|
|
return err ;
|
|
}
|
|
|
|
|