windows-nt/Source/XPSP1/NT/termsrv/regapi/regpd.c
2020-09-26 16:20:57 +08:00

841 lines
23 KiB
C

/*************************************************************************
*
* regpd.c
*
* Register APIs for Tds and Pds (transport and protocol drivers)
*
* Copyright (c) 1998 Microsoft Corporation
*
*
*************************************************************************/
/*
* Includes
*/
#include <windows.h>
#include <ksguid.h>
#include <ntddkbd.h>
#include <ntddmou.h>
#include <winstaw.h>
#include <regapi.h>
/*
* External Procedures defined here
*/
HANDLE WINAPI RegOpenServerW ( LPWSTR pServerName );
HANDLE WINAPI RegOpenServerA ( LPSTR pServerName );
LONG WINAPI RegCloseServer ( HANDLE hServer );
LONG WINAPI RegPdEnumerateW( HANDLE, PWDNAMEW, BOOLEAN, PULONG, PULONG, PPDNAMEW, PULONG );
LONG WINAPI RegPdEnumerateA( HANDLE, PWDNAMEA, BOOLEAN, PULONG, PULONG, PPDNAMEA, PULONG );
LONG WINAPI RegPdCreateW( HANDLE, PWDNAMEW, BOOLEAN, PPDNAMEW, BOOLEAN, PPDCONFIG3W, ULONG );
LONG WINAPI RegPdCreateA( HANDLE, PWDNAMEA, BOOLEAN, PPDNAMEA, BOOLEAN, PPDCONFIG3A, ULONG );
LONG WINAPI RegPdQueryW( HANDLE, PWDNAMEW, BOOLEAN, PPDNAMEW, PPDCONFIG3W, ULONG, PULONG );
LONG WINAPI RegPdQueryA( HANDLE, PWDNAMEA, BOOLEAN, PPDNAMEA, PPDCONFIG3A, ULONG, PULONG );
LONG WINAPI RegPdDeleteW( HANDLE, PWDNAMEW, BOOLEAN, PPDNAMEW );
LONG WINAPI RegPdDeleteA( HANDLE, PWDNAMEA, BOOLEAN, PPDNAMEA );
/*
* other internal Procedures used (not defined here)
*/
VOID CreatePdConfig3( HKEY, PPDCONFIG3, ULONG );
VOID QueryPdConfig3( HKEY, PPDCONFIG3, ULONG );
VOID UnicodeToAnsi( CHAR *, ULONG, WCHAR * );
VOID AnsiToUnicode( WCHAR *, ULONG, CHAR * );
VOID PdConfigU2A( PPDCONFIGA, PPDCONFIGW );
VOID PdConfigA2U( PPDCONFIGW, PPDCONFIGA );
VOID PdConfig3U2A( PPDCONFIG3A, PPDCONFIG3W );
VOID PdConfig3A2U( PPDCONFIG3W, PPDCONFIG3A );
VOID PdParamsU2A( PPDPARAMSA, PPDPARAMSW );
VOID PdParamsA2U( PPDPARAMSW, PPDPARAMSA );
VOID AsyncConfigU2A ( PASYNCCONFIGA, PASYNCCONFIGW );
VOID AsyncConfigA2U ( PASYNCCONFIGW, PASYNCCONFIGA );
/*****************************************************************************
*
* RegOpenServerA
*
*
* ENTRY:
* Machine (input)
* Name of WinFrame computer to connect to
*
* EXIT:
* handle to a server's Registry (or NULL on error)
*
****************************************************************************/
HANDLE WINAPI
RegOpenServerA(
LPSTR pServerName
)
{
HKEY hServer;
ULONG NameLength;
PWCHAR pServerNameW = NULL;
if( pServerName == NULL ) {
return( (HANDLE)HKEY_LOCAL_MACHINE );
}
NameLength = strlen( pServerName ) + 1;
pServerNameW = LocalAlloc( 0, NameLength * sizeof(WCHAR) );
if( pServerNameW == NULL ) {
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
return( NULL );
}
AnsiToUnicode( pServerNameW, NameLength*sizeof(WCHAR), pServerName );
hServer = RegOpenServerW( pServerNameW );
LocalFree( pServerNameW );
return( (HANDLE) hServer );
}
/*****************************************************************************
*
* RegOpenServerW
*
* NULL for machine name means local system.
*
* ENTRY:
* Machine (input)
* Name of WinFrame computer to connect to
*
* EXIT:
* handle to server's Registry (or NULL on error)
*
****************************************************************************/
HANDLE WINAPI
RegOpenServerW( LPWSTR pServerName ){
HKEY hKey;
if( pServerName == NULL )
return( HKEY_LOCAL_MACHINE );
else {
if( RegConnectRegistry( pServerName, HKEY_LOCAL_MACHINE, &hKey ) != ERROR_SUCCESS ){
return( NULL );
}
}
return( hKey );
}
/*****************************************************************************
*
* RegCloseServer
*
* Close a connection to a Server Registry.
*
* ENTRY:
* hServer (input)
* Handle to close
*
* EXIT:
* ERROR_SUCCESS - no error
*
****************************************************************************/
LONG WINAPI
RegCloseServer( HANDLE hServer )
{
return( RegCloseKey( (HKEY)hServer ) );
}
/*******************************************************************************
*
* RegPdEnumerateA (ANSI stub)
*
* Returns a list of configured Pds in the registry.
*
* ENTRY:
*
* see RegPdEnumerateW
*
* EXIT:
*
* see RegPdEnumerateW, plus
*
* ERROR_NOT_ENOUGH_MEMORY - the LocalAlloc failed
*
******************************************************************************/
LONG WINAPI
RegPdEnumerateA( HANDLE hServer,
PWDNAMEA pWdName,
BOOLEAN bTd,
PULONG pIndex,
PULONG pEntries,
PPDNAMEA pPdName,
PULONG pByteCount )
{
WDNAMEW WdNameW;
PPDNAMEW pBuffer = NULL, pPdNameW;
LONG Status;
ULONG Count, ByteCountW = (*pByteCount << 1);
/*
* If the caller supplied a buffer and the length is not 0,
* allocate a corresponding (*2) buffer for UNICODE strings.
*/
if ( pPdName && ByteCountW ) {
if ( !(pBuffer = LocalAlloc(0, ByteCountW)) )
return ( ERROR_NOT_ENOUGH_MEMORY );
}
/*
* Convert ANSI WdName to UNICODE.
*/
AnsiToUnicode( WdNameW, sizeof(WDNAMEW), pWdName );
/*
* Enumerate Pds
*/
pPdNameW = pBuffer;
Status = RegPdEnumerateW( hServer,
WdNameW,
bTd,
pIndex,
pEntries,
pPdNameW,
&ByteCountW );
/*
* Always /2 the resultant ByteCount (whether sucessful or not).
*/
*pByteCount = (ByteCountW >> 1);
/*
* If the function completed sucessfully and caller
* (and stub) defined a buffer to copy into, perform conversion
* from UNICODE to ANSI. Note: sucessful return may have copied
* 0 items from registry (end of enumeration), denoted by *pEntries
* == 0.
*/
if ( ((Status == ERROR_SUCCESS) || (Status == ERROR_NO_MORE_ITEMS))
&& pPdNameW && pPdName ) {
for ( Count = *pEntries; Count; Count-- ) {
UnicodeToAnsi( pPdName, sizeof(PDNAMEA), pPdNameW );
(char*)pPdName += sizeof(PDNAMEA);
(char*)pPdNameW += sizeof(PDNAMEW);
}
}
/*
* If we defined a buffer, free it now, then return the status
* of the Reg...EnumerateW function call.
*/
if ( pBuffer )
LocalFree(pBuffer);
return ( Status );
}
/*******************************************************************************
*
* RegPdEnumerateW (UNICODE)
*
* Returns a list of configured Pds in the registry.
*
* ENTRY:
*
* hServer (input)
* Handle to WinFrame Server
* pWdName (input)
* Points to the wdname to enumerate pds for
* bTd (input)
* TRUE to enumerate Transport Drivers (Tds),
* FALSE to enumerate Protocol Drivers (Pds)
* pIndex (input/output)
* Specifies the subkey index for the \Citrix\Wds\<wdname>\<Pd or Td>
* subkeys in the registry. Should be set to 0 for the initial call,
* and supplied again (as modified by this function) for multi-call
* enumeration.
* pEntries (input/output)
* Points to a variable specifying the number of entries requested.
* If the number requested is 0xFFFFFFFF, the function returns as
* many entries as possible. When the function finishes successfully,
* the variable pointed to by the pEntries parameter contains the
* number of entries actually read.
* pPdName (input)
* Points to the buffer to receive the enumeration results, which are
* returned as an array of PDNAME structures. If this parameter is
* NULL, then no data will be copied, but just an enumeration count will
* be made.
* pByteCount (input/output)
* Points to a variable that specifies the size, in bytes, of the
* pPdName parameter. If the buffer is too small to receive even
* one entry, the function returns an error code (ERROR_OUTOFMEMORY)
* and this variable receives the required size of the buffer for a
* single subkey. When the function finishes sucessfully, the variable
* pointed to by the pByteCount parameter contains the number of bytes
* actually stored in pPdName.
*
* EXIT:
*
* "No Error" codes:
* ERROR_SUCCESS - The enumeration completed as requested and there
* are more Pds subkeys (PDNAMEs) to be read.
* ERROR_NO_MORE_ITEMS - The enumeration completed as requested and there
* are no more Pds subkeys (PDNAMEs) to be read.
*
* "Error" codes:
* ERROR_OUTOFMEMORY - The pPdName buffer is too small for even one entry.
* ERROR_CANTOPEN - The \Citrix\Wds\<wdname>\<Pd or Td> key can't be opened.
*
******************************************************************************/
LONG WINAPI
RegPdEnumerateW( HANDLE hServer,
PWDNAMEW pWdName,
BOOLEAN bTd,
PULONG pIndex,
PULONG pEntries,
PPDNAMEW pPdName,
PULONG pByteCount )
{
LONG Status;
HKEY Handle;
ULONG Count;
ULONG i;
HKEY hkey_local_machine;
WCHAR KeyString[256];
if( hServer == NULL )
hkey_local_machine = HKEY_LOCAL_MACHINE;
else
hkey_local_machine = hServer;
/*
* Get the number of names to return
*/
Count = pPdName ?
min( *pByteCount / sizeof(PDNAME), *pEntries ) :
(ULONG) -1;
*pEntries = *pByteCount = 0;
/*
* Make sure buffer is big enough for at least one name
*/
if ( Count == 0 ) {
*pByteCount = sizeof(PDNAME);
return( ERROR_OUTOFMEMORY );
}
/*
* Open registry (LOCAL_MACHINE\....\Citrix\Wds\<wdname>\<Pd or Td>)
*/
wcscpy( KeyString, WD_REG_NAME );
wcscat( KeyString, L"\\" );
wcscat( KeyString, pWdName );
wcscat( KeyString, bTd ? TD_REG_NAME : PD_REG_NAME );
if ( RegOpenKeyEx( hkey_local_machine, KeyString, 0,
KEY_ENUMERATE_SUB_KEYS, &Handle ) != ERROR_SUCCESS ) {
return( ERROR_CANTOPEN );
}
/*
* Get list of Tds or Pds
*/
for ( i = 0; i < Count; i++ ) {
PDNAME PdName;
if ( (Status = RegEnumKey(Handle, *pIndex, PdName,
sizeof(PDNAME)/sizeof(TCHAR) )) != ERROR_SUCCESS )
break;
/*
* If caller supplied a buffer, then copy the PdName
* and increment the pointer and byte count. Always increment the
* entry count and index for the next iteration.
*/
if ( pPdName ) {
wcscpy( pPdName, PdName );
(char*)pPdName += sizeof(PDNAME);
*pByteCount += sizeof(PDNAME);
}
(*pEntries)++;
(*pIndex)++;
}
/*
* Close registry
*/
RegCloseKey( Handle );
return( Status );
}
/*******************************************************************************
*
* RegPdCreateA (ANSI stub)
*
* Creates a new Pd in the registry or updates an existing entry.
* (See RegPdCreateW)
*
* ENTRY:
*
* see RegPdCreateW
*
* EXIT:
*
* see RegPdCreateW
*
******************************************************************************/
LONG WINAPI
RegPdCreateA( HANDLE hServer,
PWDNAMEA pWdName,
BOOLEAN bTd,
PPDNAMEA pPdName,
BOOLEAN bCreate,
PPDCONFIG3A pPdConfig,
ULONG PdConfigLength )
{
PDNAMEW PdNameW;
WDNAMEW WdNameW;
PDCONFIG3W PdConfig3W;
/*
* Validate target buffer size.
*/
if ( PdConfigLength < sizeof(PDCONFIG3A) )
return( ERROR_INSUFFICIENT_BUFFER );
/*
* Convert ANSI WdName and PdName to UNICODE.
*/
AnsiToUnicode( WdNameW, sizeof(WDNAMEW), pWdName );
AnsiToUnicode( PdNameW, sizeof(PDNAMEW), pPdName );
/*
* Copy PDCONFIG3A elements to PDCONFIG3W elements.
*/
PdConfig3A2U( &PdConfig3W, pPdConfig );
/*
* Call RegPdCreateW & return it's status.
*/
return ( RegPdCreateW( hServer,
WdNameW,
bTd,
PdNameW,
bCreate,
&PdConfig3W,
sizeof(PdConfig3W)) );
}
/*******************************************************************************
*
* RegPdCreateW (UNICODE)
*
* Creates a new Pd in the registry or updates an existing entry. The
* state of the bCreate flag determines whether this function will expect
* to create a new Pd entry (bCreate == TRUE) or expects to update an
* existing entry (bCreate == FALSE).
*
* ENTRY:
* hServer (input)
* Handle to WinFrame Server
* pWdName (input)
* Points to the wdname to create pd for
* bTd (input)
* TRUE to create a Transport Driver (Td),
* FALSE to create a Protocol Driver (Pd)
* pPdName (input)
* Name of a new or exisiting Pd in the registry.
* bCreate (input)
* TRUE if this is a creation of a new Pd
* FALSE if this is an update to an existing Pd
* pPdConfig (input)
* Pointer to a PDCONFIG3 structure containing configuration
* information for the specified Pd name.
* PdConfigLength (input)
* Specifies the length in bytes of the pPdConfig buffer.
*
* EXIT:
* ERROR_SUCCESS - no error
*
* ERROR_INSUFFICIENT_BUFFER - pPdConfig buffer too small
* ERROR_FILE_NOT_FOUND - can't open ...\Citrix\Wds\<wdname>\<Pd or Td> key
* ERROR_CANNOT_MAKE - can't create Pd key (registry problem)
* ERROR_ALREADY_EXISTS - create; but Pd key was already present
* ERROR_CANTOPEN - update; but Pd key could not be opened
*
******************************************************************************/
LONG WINAPI
RegPdCreateW( HANDLE hServer,
PWDNAMEW pWdName,
BOOLEAN bTd,
PPDNAMEW pPdName,
BOOLEAN bCreate,
PPDCONFIG3W pPdConfig,
ULONG PdConfigLength )
{
HKEY Handle;
HKEY Handle1;
DWORD Disp;
HKEY hkey_local_machine;
WCHAR KeyString[256];
if( hServer == NULL )
hkey_local_machine = HKEY_LOCAL_MACHINE;
else
hkey_local_machine = hServer;
/*
* Validate length of buffer
*/
if ( PdConfigLength < sizeof(PDCONFIG3) )
return( ERROR_INSUFFICIENT_BUFFER );
/*
* Open registry (LOCAL_MACHINE\....\Citrix\Wds\<wdname>\<Pd or Td>)
*/
wcscpy( KeyString, WD_REG_NAME );
wcscat( KeyString, L"\\" );
wcscat( KeyString, pWdName );
wcscat( KeyString, bTd ? TD_REG_NAME : PD_REG_NAME );
if ( RegOpenKeyEx( hkey_local_machine, KeyString, 0,
KEY_ALL_ACCESS, &Handle1 ) != ERROR_SUCCESS ) {
return( ERROR_FILE_NOT_FOUND );
}
if ( bCreate ) {
/*
* Create requested: create a registry key for the specified
* Pd name.
*/
if ( RegCreateKeyEx( Handle1, pPdName, 0, NULL,
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
NULL, &Handle, &Disp ) != ERROR_SUCCESS ) {
RegCloseKey( Handle1 );
return( ERROR_CANNOT_MAKE );
}
/*
* If an existing key was returned instead of a new one being
* created, return error (don't update).
*/
if ( Disp != REG_CREATED_NEW_KEY ) {
RegCloseKey( Handle1 );
RegCloseKey( Handle );
return( ERROR_ALREADY_EXISTS );
}
} else {
/*
* Update requested: open the registry key for the specified
* Pd name.
*/
if ( RegOpenKeyEx( Handle1, pPdName, 0, KEY_ALL_ACCESS,
&Handle ) != ERROR_SUCCESS ) {
RegCloseKey( Handle1 );
return( ERROR_CANTOPEN );
}
}
RegCloseKey( Handle1 );
/*
* Save Pd information
*/
CreatePdConfig3( Handle, pPdConfig, 0 );
/*
* Close registry handle
*/
RegCloseKey( Handle );
return( ERROR_SUCCESS );
}
/*******************************************************************************
*
* RegPdQueryA (ANSI stub)
*
* Query configuration information of a Pd in the registry.
*
* ENTRY:
*
* see RegPdQueryW
*
* EXIT:
*
* see RegPdQueryW
*
******************************************************************************/
LONG WINAPI
RegPdQueryA( HANDLE hServer,
PWDNAMEA pWdName,
BOOLEAN bTd,
PPDNAMEA pPdName,
PPDCONFIG3A pPdConfig,
ULONG PdConfigLength,
PULONG pReturnLength )
{
PDNAMEW PdNameW;
WDNAMEW WdNameW;
PDCONFIG3W PdConfig3W;
LONG Status;
ULONG ReturnLengthW;
/*
* Validate length and zero-initialize the destination
* PDCONFIG3A structure.
*/
if ( PdConfigLength < sizeof(PDCONFIG3A) )
return( ERROR_INSUFFICIENT_BUFFER );
memset(pPdConfig, 0, PdConfigLength);
/*
* Convert ANSI WdName and PdName to UNICODE.
*/
AnsiToUnicode(WdNameW, sizeof(WDNAMEW), pWdName);
AnsiToUnicode(PdNameW, sizeof(PDNAMEW), pPdName);
/*
* Query Pd.
*/
if ( (Status = RegPdQueryW( hServer,
WdNameW,
bTd,
PdNameW,
&PdConfig3W,
sizeof(PDCONFIG3W),
&ReturnLengthW)) != ERROR_SUCCESS )
return ( Status );
/*
* Copy PDCONFIG3W elements to PDCONFIG3A elements.
*/
PdConfig3U2A( pPdConfig, &PdConfig3W );
*pReturnLength = sizeof(PDCONFIG3A);
return( ERROR_SUCCESS );
}
/*******************************************************************************
*
* RegPdQueryW (UNICODE)
*
* Query configuration information of a Pd in the registry.
*
* ENTRY:
* hServer (input)
* Handle to WinFrame Server
* pWdName (input)
* Points to the wdname to query pd for
* bTd (input)
* TRUE to query a Transport Driver (Td),
* FALSE to query a Protocol Driver (Pd)
* pPdName (input)
* Name of an exisiting Pd in the registry.
* pPdConfig (input)
* Pointer to a PDCONFIG3 structure that will receive
* information about the specified Pd name.
* PdConfigLength (input)
* Specifies the length in bytes of the pPdConfig buffer.
* pReturnLength (output)
* Receives the number of bytes placed in the pPdConfig buffer.
*
* EXIT:
* ERROR_SUCCESS - no error
*
******************************************************************************/
LONG WINAPI
RegPdQueryW( HANDLE hServer,
PWDNAMEW pWdName,
BOOLEAN bTd,
PPDNAMEW pPdName,
PPDCONFIG3W pPdConfig,
ULONG PdConfigLength,
PULONG pReturnLength )
{
HKEY Handle;
HKEY Handle1;
HKEY hkey_local_machine;
WCHAR KeyString[256];
if( hServer == NULL )
hkey_local_machine = HKEY_LOCAL_MACHINE;
else
hkey_local_machine = hServer;
/*
* Validate length and zero-initialize the destination
* PDCONFIG3A structure.
*/
if ( PdConfigLength < sizeof(PDCONFIG3) )
return( ERROR_INSUFFICIENT_BUFFER );
memset(pPdConfig, 0, PdConfigLength);
/*
* Open registry (LOCAL_MACHINE\....\Citrix\Wds\<wdname>\<Pd or Td>)
*/
wcscpy( KeyString, WD_REG_NAME );
wcscat( KeyString, L"\\" );
wcscat( KeyString, pWdName );
wcscat( KeyString, bTd ? TD_REG_NAME : PD_REG_NAME );
if ( RegOpenKeyEx( hkey_local_machine, KeyString, 0,
KEY_READ, &Handle1 ) != ERROR_SUCCESS ) {
return( ERROR_FILE_NOT_FOUND );
}
/*
* Now try to open the specified Pd
*/
if ( RegOpenKeyEx( Handle1, pPdName, 0,
KEY_READ, &Handle ) != ERROR_SUCCESS ) {
RegCloseKey( Handle1 );
return( ERROR_FILE_NOT_FOUND );
}
RegCloseKey( Handle1 );
/*
* Query PDCONFIG3 Structure
*/
QueryPdConfig3( Handle, pPdConfig, 0 );
/*
* Close registry
*/
RegCloseKey( Handle );
*pReturnLength = sizeof(PDCONFIG3);
return( ERROR_SUCCESS );
}
/*******************************************************************************
*
* RegPdDeleteA (ANSI stub)
*
* Deletes a Pd from the registry.
*
* ENTRY:
*
* see RegPdDeleteW
*
* EXIT:
*
* see RegPdDeleteW
*
******************************************************************************/
LONG WINAPI
RegPdDeleteA( HANDLE hServer,
PWDNAMEA pWdName,
BOOLEAN bTd,
PPDNAMEA pPdName )
{
WDNAMEW WdNameW;
PDNAMEW PdNameW;
AnsiToUnicode( WdNameW, sizeof(WdNameW), pWdName );
AnsiToUnicode( PdNameW, sizeof(PdNameW), pPdName );
return ( RegPdDeleteW ( hServer, WdNameW, bTd, PdNameW ) );
}
/*******************************************************************************
*
* RegPdDeleteW (UNICODE)
*
* Deletes a Pd from the registry.
*
* ENTRY:
* hServer (input)
* Handle to WinFrame Server
* pWdName (input)
* Points to the wdname to delete pd from
* bTd (input)
* TRUE to delete a Transport Driver (Td),
* FALSE to delete a Protocol Driver (Pd)
* pPdName (input)
* Name of a Pd to delete from the registry.
*
* EXIT:
* ERROR_SUCCESS - no error
*
******************************************************************************/
LONG WINAPI
RegPdDeleteW( HANDLE hServer,
PWDNAMEW pWdName,
BOOLEAN bTd,
PPDNAMEW pPdName )
{
LONG Status;
HKEY Handle;
HKEY Handle1;
HKEY hkey_local_machine;
WCHAR KeyString[256];
if( hServer == NULL )
hkey_local_machine = HKEY_LOCAL_MACHINE;
else
hkey_local_machine = hServer;
/*
* Open registry (LOCAL_MACHINE\....\Citrix\Wds\<wdname>\<Pd or Td>)
*/
wcscpy( KeyString, WD_REG_NAME );
wcscat( KeyString, L"\\" );
wcscat( KeyString, pWdName );
wcscat( KeyString, bTd ? TD_REG_NAME : PD_REG_NAME );
if ( RegOpenKeyEx( hkey_local_machine, KeyString, 0,
KEY_READ, &Handle ) != ERROR_SUCCESS ) {
return( ERROR_FILE_NOT_FOUND );
}
/*
* Now try to open the specified Pd
*/
if ( RegOpenKeyEx( Handle, pPdName, 0,
KEY_READ, &Handle1 ) != ERROR_SUCCESS ) {
RegCloseKey( Handle );
return( ERROR_FILE_NOT_FOUND );
}
/*
* Close the Pd key handle, delete the Pd,
* and close the parent handle.
*/
RegCloseKey( Handle1 );
Status = RegDeleteKey( Handle, pPdName );
RegCloseKey( Handle );
return( Status );
}