WindowsXP-SP1/com/rpc/runtime/mtrt/miscnt.cxx
2020-09-30 16:53:49 +02:00

2449 lines
68 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (C) Microsoft Corporation, 1991 - 1999
Module Name:
miscnt.cxx
Abstract:
This file contains NT specific implementations of miscellaneous
routines.
Author:
Michael Montague (mikemon) 25-Nov-1991
Revision History:
Kamen Moutafov (KamenM) Dec 99 - Feb 2000 - Support for cell debugging stuff
Kamen Moutafov (KamenM) Mar-2000 Support for extended error info
--*/
#include <precomp.hxx>
#include <rpccfg.h>
#include <CharConv.hxx>
static const char *RPC_REGISTRY_PROTOCOLS =
"Software\\Microsoft\\Rpc\\ClientProtocols";
static const char *RPC_REGISTRY_PROTOCOL_IDS =
"Software\\Microsoft\\Rpc\\AdditionalProtocols";
static const RPC_CHAR *RPC_REGISTRY_DEFAULT_SECURITY_DLL =
L"System\\CurrentControlSet\\Control\\SecurityProviders";
// N.B. This value must agree with the key specified in the system.adm file
static const RPC_CHAR *RPC_POLICY_SETTINGS =
L"Software\\Policies\\Microsoft\\Windows NT\\Rpc";
static const RPC_CHAR *RPC_REGISTRY_IMAGE_FILE_EXEC =
L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\";
static const RPC_CHAR *RPC_REGISTRY_THREAD_THROTTLE =
L"\\RpcThreadPoolThrottle";
const int IMAGE_FILE_EXEC_LENGTH = 75;
const int THREAD_THROTTLE_LENGTH = 24;
#define MAX_ENDPOINT_LENGTH 128
#define MAX_ID_LENGTH 6
#define MAX_DLL_NAME 128
typedef struct
{
const RPC_CHAR * RpcProtocolSequence;
const RPC_CHAR * TransportInterfaceDll;
unsigned long TransportId;
} RPC_PROTOCOL_SEQUENCE_MAP;
static const RPC_PROTOCOL_SEQUENCE_MAP RpcProtocolSequenceMap[] =
{
{
RPC_CONST_STRING("ncacn_np"),
RPC_CONST_STRING("rpcrt4.dll"),
NMP_TOWER_ID
},
{
RPC_CONST_STRING("ncacn_ip_tcp"),
RPC_CONST_STRING("rpcrt4.dll"),
TCP_TOWER_ID
},
#ifdef SPX_ON
{
RPC_CONST_STRING("ncacn_spx"),
RPC_CONST_STRING("rpcrt4.dll"),
SPX_TOWER_ID
},
#endif
{
RPC_CONST_STRING("ncadg_ip_udp"),
RPC_CONST_STRING("rpcrt4.dll"),
UDP_TOWER_ID
},
#ifdef IPX_ON
{
RPC_CONST_STRING("ncadg_ipx"),
RPC_CONST_STRING("rpcrt4.dll"),
IPX_TOWER_ID
},
#endif
#ifdef NETBIOS_ON
{
RPC_CONST_STRING("ncacn_nb_tcp"),
RPC_CONST_STRING("rpcrt4.dll"),
NB_TOWER_ID
},
{
RPC_CONST_STRING("ncacn_nb_ipx"),
RPC_CONST_STRING("rpcrt4.dll"),
NB_TOWER_ID
},
{
RPC_CONST_STRING("ncacn_nb_nb"),
RPC_CONST_STRING("rpcrt4.dll"),
NB_TOWER_ID
},
#endif
#ifdef APPLETALK_ON
{
RPC_CONST_STRING("ncacn_at_dsp"),
RPC_CONST_STRING("rpcrt4.dll"),
DSP_TOWER_ID
},
#endif
{
RPC_CONST_STRING("ncacn_http"),
RPC_CONST_STRING("rpcrt4.dll"),
HTTP_TOWER_ID
},
{
RPC_CONST_STRING("ncadg_cluster"),
RPC_CONST_STRING("rpcrt4.dll"),
CDP_TOWER_ID
},
#ifdef NCADG_MQ_ON
{
RPC_CONST_STRING("ncadg_mq"),
RPC_CONST_STRING("rpcrt4.dll"),
MQ_TOWER_ID
},
#endif
#ifdef BANYAN_ON
{
RPC_CONST_STRING("ncacn_vns_spp"),
RPC_CONST_STRING("rpcrt4.dll"),
SPP_TOWER_ID
},
#endif
{
RPC_CONST_STRING("ncalrpc"),
0,
0
},
};
const int RpcProtseqMapLength = (sizeof(RpcProtocolSequenceMap)
/ sizeof(RPC_PROTOCOL_SEQUENCE_MAP));
static const RPC_PROTOCOL_SEQUENCE_MAP RpcUseAllProtseqMap[] =
{
{
RPC_CONST_STRING("ncacn_np"),
RPC_CONST_STRING("rpcrt4.dll"),
NMP_TOWER_ID
},
{
RPC_CONST_STRING("ncalrpc"),
0,
0
},
};
const int RpcUseAllProtseqMapLength = (sizeof(RpcUseAllProtseqMap)
/ sizeof(RPC_PROTOCOL_SEQUENCE_MAP));
typedef struct
{
unsigned char * RpcProtocolSequence;
unsigned char * RpcSsEndpoint;
unsigned long TransportId;
} RPC_PROTOCOL_INFO;
static const RPC_PROTOCOL_INFO StaticProtocolMapping[] =
{
{
(unsigned char *)"ncacn_np",
(unsigned char *)"\\pipe\\epmapper",
0x0F
}
};
RPC_PROTOCOL_INFO * AdditionalProtocols = 0;
unsigned long TotalAdditionalProtocols = 0;
static const char *RPC_REGISTRY_SECURITY_PROVIDERS =
"Software\\Microsoft\\Rpc\\SecurityService";
static const char *RPC_MISC_SETTINGS =
"Software\\Microsoft\\Rpc";
BOOL DefaultProviderRead = FALSE;
DWORD DefaultAuthLevel = RPC_C_AUTHN_LEVEL_CONNECT;
DWORD DefaultProviderId = RPC_C_AUTHN_WINNT;
RPC_CHAR *DefaultSecurityDLL = L"secur32.dll";
BOOL DefaultSecurityDLLRead = FALSE;
void
GetMaxRpcSizeAndThreadPoolParameters (
void
)
{
HKEY RegistryKey;
DWORD Result;
DWORD RegStatus;
DWORD Type;
DWORD DwordSize = sizeof(DWORD);
RPC_CHAR KeyName[MAX_PATH + IMAGE_FILE_EXEC_LENGTH + THREAD_THROTTLE_LENGTH];
const RPC_CHAR * ModuleName;
int ModuleLength;
RPC_CHAR *CurrentPos;
//
// Get the default Rpc size.
//
RegStatus = RegOpenKeyExA(
HKEY_LOCAL_MACHINE,
(LPSTR) RPC_MISC_SETTINGS,
0L, KEY_READ, //Reserved
&RegistryKey
);
if ( RegStatus != ERROR_SUCCESS )
{
return;
}
RegStatus = RegQueryValueExA(
RegistryKey,
"MaxRpcSize",
0,
&Type,
(LPBYTE) &Result,
&DwordSize
);
if (RegStatus == ERROR_SUCCESS
&& Type == REG_DWORD)
{
gMaxRpcSize = Result;
}
RegCloseKey(RegistryKey);
//
// Find out the .EXE name.
//
ModuleName = FastGetImageBaseName();
ModuleLength = RpcpStringLength(ModuleName);
CurrentPos = KeyName;
RpcpMemoryCopy(CurrentPos,
RPC_REGISTRY_IMAGE_FILE_EXEC,
IMAGE_FILE_EXEC_LENGTH * 2);
CurrentPos += IMAGE_FILE_EXEC_LENGTH - 1;
RpcpMemoryCopy(CurrentPos,
ModuleName,
ModuleLength * 2);
CurrentPos += ModuleLength;
RpcpMemoryCopy(CurrentPos,
RPC_REGISTRY_THREAD_THROTTLE,
THREAD_THROTTLE_LENGTH * 2);
RegStatus = RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
KeyName,
0L, KEY_READ, //Reserved
&RegistryKey
);
if ( RegStatus != ERROR_SUCCESS )
{
return;
}
DwordSize = sizeof(DWORD);
RegStatus = RegQueryValueExA(
RegistryKey,
"ProrateMax",
0,
&Type,
(LPBYTE) &Result,
&DwordSize
);
if (RegStatus == ERROR_SUCCESS
&& Type == REG_DWORD)
{
gProrateMax = Result;
}
DwordSize = sizeof(DWORD);
RegStatus = RegQueryValueExA(
RegistryKey,
"ProrateFactor",
0,
&Type,
(LPBYTE) &Result,
&DwordSize
);
if (RegStatus == ERROR_SUCCESS
&& Type == REG_DWORD)
{
gProrateFactor = Result;
}
DwordSize = sizeof(DWORD);
RegStatus = RegQueryValueExA(
RegistryKey,
"ProrateStart",
0,
&Type,
(LPBYTE) &Result,
&DwordSize
);
if (RegStatus == ERROR_SUCCESS
&& Type == REG_DWORD)
{
gProrateStart = Result;
}
RegCloseKey(RegistryKey);
// if any of these values are invalid, turn it off
if ((gProrateFactor == 0) || (gProrateMax == 0))
gProrateStart = 0;
}
BOOL
GetDefaultLevel()
{
HKEY RegistryKey;
DWORD Result;
DWORD RegStatus;
DWORD Type;
DWORD DwordSize = sizeof(DWORD);
//
// Get the default provider level.
//
RegStatus = RegOpenKeyExA(
HKEY_LOCAL_MACHINE,
(LPSTR) RPC_REGISTRY_SECURITY_PROVIDERS,
0L, KEY_READ, //Reserved
&RegistryKey
);
if ( RegStatus != ERROR_SUCCESS )
{
return FALSE;
}
RegStatus = RegQueryValueExA(
RegistryKey,
"DefaultAuthLevel",
0,
&Type,
(LPBYTE) &Result,
&DwordSize
);
if (RegStatus == ERROR_CANTOPEN ||
RegStatus == ERROR_CANTREAD )
{
RegCloseKey(RegistryKey);
return TRUE;
}
if ( RegStatus != ERROR_SUCCESS )
{
RegCloseKey(RegistryKey);
return FALSE;
}
if ( Type != REG_DWORD )
{
RegCloseKey(RegistryKey);
return TRUE;
}
if (Result >= RPC_C_AUTHN_LEVEL_CONNECT &&
Result <= RPC_C_AUTHN_LEVEL_PKT_PRIVACY )
{
DefaultAuthLevel = Result;
}
RegCloseKey(RegistryKey);
return TRUE;
}
void
RpcpGetDefaultSecurityProviderInfo()
{
if (DefaultProviderRead)
{
return;
}
if (GetDefaultLevel())
{
DefaultProviderRead = TRUE;
}
}
RPC_STATUS
GetDefaultSecurityDll (
IN RPC_CHAR *DllName,
IN ULONG DllNameLength
)
{
HKEY RegistryKey;
DWORD RegStatus;
RPC_CHAR *DuplicateDllName;
DWORD Type;
if (DefaultSecurityDLLRead == FALSE)
{
RegStatus = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
RPC_REGISTRY_DEFAULT_SECURITY_DLL,
0L, KEY_READ, //Reserved
&RegistryKey
);
if ( RegStatus != ERROR_SUCCESS )
{
if (RegStatus == ERROR_FILE_NOT_FOUND)
{
DefaultSecurityDLLRead = TRUE;
return RPC_S_OK;
}
return(RPC_S_UNKNOWN_AUTHN_SERVICE);
}
RegStatus = RegQueryValueEx(
RegistryKey,
L"ClientDll",
0,
&Type,
(unsigned char *)DllName,
&DllNameLength
);
if ( RegStatus != ERROR_SUCCESS )
{
RegCloseKey(RegistryKey);
if (RegStatus == ERROR_FILE_NOT_FOUND)
{
DefaultSecurityDLLRead = TRUE;
return RPC_S_OK;
}
return(RPC_S_UNKNOWN_AUTHN_SERVICE);
}
if (Type != REG_SZ)
{
RegCloseKey(RegistryKey);
return(RPC_S_UNKNOWN_AUTHN_SERVICE);
}
DuplicateDllName = DuplicateString(DllName);
RegCloseKey(RegistryKey);
if (DuplicateDllName)
{
DefaultSecurityDLL = DuplicateDllName;
DefaultSecurityDLLRead = TRUE;
}
else
{
return RPC_S_OUT_OF_MEMORY;
}
}
return RPC_S_OK;
}
RPC_STATUS
RpcGetSecurityProviderInfo(
IN unsigned long AuthnId,
OUT RPC_CHAR **Dll,
OUT unsigned long PAPI * Count
)
{
DWORD RegStatus, Ignore, NumberOfValues, MaximumValueLength;
unsigned long DllNameLength = MAX_DLL_NAME+1;
DWORD ClassLength = 64, Type;
RPC_CHAR DllName[MAX_DLL_NAME+1];
FILETIME LastWriteTime;
HKEY RegistryKey;
unsigned char ClassName[64];
RPC_STATUS Status = RPC_S_OK;
char AuthnIdZ[8];
RPC_CHAR unicodeAuthnIdZ[8];
RPC_CHAR *pAuthnIdZ;
RPC_CHAR *ActualDllName;
RpcItoa(AuthnId, AuthnIdZ, 10);
RegStatus = RegOpenKeyExA(
HKEY_LOCAL_MACHINE,
(LPSTR) RPC_REGISTRY_SECURITY_PROVIDERS,
0L, KEY_READ, //Reserved
&RegistryKey
);
if ( RegStatus != ERROR_SUCCESS )
{
return(RPC_S_UNKNOWN_AUTHN_SERVICE);
}
RegStatus = RegQueryInfoKeyA(
RegistryKey,
(LPSTR) ClassName,
&ClassLength,
0, //Reserved
&Ignore,
&Ignore,
&Ignore,
&NumberOfValues,
&Ignore,
&MaximumValueLength,
&Ignore,
&LastWriteTime
);
if ( (RegStatus != ERROR_SUCCESS) || (NumberOfValues < 2) )
{
RegStatus = RegCloseKey(RegistryKey);
ASSERT( RegStatus == ERROR_SUCCESS );
return(RPC_S_UNKNOWN_AUTHN_SERVICE);
}
*Count = NumberOfValues - 2; //Gross
SimpleAnsiToUnicode(AuthnIdZ, unicodeAuthnIdZ);
pAuthnIdZ = unicodeAuthnIdZ;
RegStatus = RegQueryValueEx(
RegistryKey,
(const RPC_SCHAR *)pAuthnIdZ,
0,
&Type,
(unsigned char *)DllName,
&DllNameLength
);
RegCloseKey(RegistryKey);
if (RegStatus != ERROR_SUCCESS)
{
RegStatus = GetDefaultSecurityDll(
DllName,
DllNameLength);
if (RegStatus == RPC_S_OK)
ActualDllName = DefaultSecurityDLL;
}
else
{
ActualDllName = DllName;
}
if (RegStatus == ERROR_SUCCESS)
{
*Dll = DuplicateString(ActualDllName);
if (*Dll == 0)
{
RegStatus = RPC_S_OUT_OF_MEMORY;
}
}
else
{
RegStatus = RPC_S_UNKNOWN_AUTHN_SERVICE;
}
return(RegStatus);
}
DWORD * FourLeggedPackages = 0;
DWORD NullPackageList[] = { 0 };
BOOL
ReadPackageLegInfo()
/*++
Routine Description:
NT 4.0 and previous versions allowed only two or three legs to set up the
security context. Two were represented on the wire as BIND then BIND_ACK;
three added an AUTH3 packet. When Jeff added 4- and 6-leg support, he
made the sequence BIND, BIND-ACK, ALTER-CXT, ALTER-CXT-RESPONSE. Sadly,
it turns out to be impossible for RPC to tell whether a given package wants
three or four legs, so the client would have to guess whether to send
an AUTH3 or an ALTER-CXT to an NT 4 server. To solve this we are adding a
registry value that lists all the providers that need more than three legs.
The format, in regdmp.exe form, is
\Registry\Machine\Software\Microsoft\Rpc
Four-legged packages = REG_MULTI_SZ "16" "18" ""
This function opens the registry and converts this data into an in-memory
array of DWORD package IDs.
Not all packages are in this list; see GetPackageLegCount() for details.
Return Values:
TRUE = the registry data was read, or the value does not exist.
Calling this function again will have no effect.
FALSE = there was a problem reading the data in the registry.
You can call the fn later and it will try again.
--*/
{
DWORD Size = 0;
DWORD RegStatus;
DWORD Type;
HKEY RegistryKey;
wchar_t * Strings;
if (FourLeggedPackages)
{
return TRUE;
}
SecurityCritSect->VerifyOwned();
// open key;
RegStatus = RegOpenKeyExA(
HKEY_LOCAL_MACHINE,
(LPSTR) RPC_REGISTRY_SECURITY_PROVIDERS,
0L, KEY_READ, //Reserved
&RegistryKey
);
if ( RegStatus != ERROR_SUCCESS )
{
return FALSE;
}
// get size of strings
RegStatus = RegQueryValueExW(
RegistryKey,
L"Four-legged packages",
0,
&Type,
0,
&Size
);
if (RegStatus == ERROR_FILE_NOT_FOUND )
{
RegCloseKey(RegistryKey);
FourLeggedPackages = NullPackageList;
return TRUE;
}
if ( RegStatus != ERROR_SUCCESS )
{
RegCloseKey(RegistryKey);
return FALSE;
}
//
// Place an upper bound on the size to avoid hacker attacks.
//
if ( Type != REG_MULTI_SZ || Size > 4000)
{
RegCloseKey(RegistryKey);
FourLeggedPackages = NullPackageList;
return TRUE;
}
// get string data.
Strings = (wchar_t *) _alloca( Size );
RegStatus = RegQueryValueExW(
RegistryKey,
L"Four-legged packages",
0,
&Type,
(unsigned char *) Strings,
&Size
);
RegCloseKey(RegistryKey);
if (RegStatus == ERROR_CANTOPEN ||
RegStatus == ERROR_CANTREAD )
{
FourLeggedPackages = NullPackageList;
return TRUE;
}
if ( RegStatus != ERROR_SUCCESS )
{
return FALSE;
}
if ( Type != REG_MULTI_SZ )
{
FourLeggedPackages = NullPackageList;
return TRUE;
}
// count strings; the buffer is terminated by an empty string that will be counted.
int Count = 0;
wchar_t * p;
for (p=Strings; p < Strings + Size; ++p)
{
if (*p == '\0')
{
++Count;
}
}
// allocate memory.
DWORD * LegData = new DWORD[Count];
if (!LegData)
{
return FALSE;
}
// transfer data
int i;
wchar_t * new_p;
for (i=0, p=Strings; p < Strings + Size; ++i, p = new_p+1)
{
LegData[i] = wcstoul(p, &new_p, 10);
if (*new_p != '\0')
{
// The string is badly formatted. Eliminate it.
--i;
new_p += wcslen(new_p);
}
}
if (FourLeggedPackages && FourLeggedPackages != NullPackageList)
{
delete FourLeggedPackages;
}
FourLeggedPackages = LegData;
return TRUE;
}
RPC_STATUS
LoadAdditionalTransportInfo(
)
{
DWORD RegStatus, Index, Ignore, NumberOfValues, MaximumValueLength;
DWORD ClassLength = 64, ProtseqLength, IgnoreLength;
BYTE Protseq[MAX_PROTSEQ_LENGTH+1];
BYTE MaxValueData[MAX_ENDPOINT_LENGTH+MAX_ID_LENGTH+2+8];
FILETIME LastWriteTime;
HKEY RegistryKey;
unsigned char ClassName[64];
char * Value;
RPC_PROTOCOL_INFO * AdditionalProtocolsInfo;
RPC_STATUS Status = RPC_S_OK;
unsigned long Length, TransportId;
RegStatus = RegOpenKeyExA(
HKEY_LOCAL_MACHINE,
(LPSTR) RPC_REGISTRY_PROTOCOL_IDS,
0L, KEY_READ, //Reserved
&RegistryKey
);
if ( RegStatus != ERROR_SUCCESS )
{
return(RPC_S_INVALID_RPC_PROTSEQ);
}
RegStatus = RegQueryInfoKeyA(
RegistryKey,
(LPSTR) ClassName,
&ClassLength,
0, //Reserved
&Ignore,
&Ignore,
&Ignore,
&NumberOfValues,
&Ignore,
&MaximumValueLength,
&Ignore,
&LastWriteTime
);
if ( (RegStatus != ERROR_SUCCESS) || (NumberOfValues == 0) )
{
RegStatus = RegCloseKey(RegistryKey);
ASSERT( RegStatus == ERROR_SUCCESS );
return(RPC_S_INVALID_RPC_PROTSEQ);
}
//Allocate a table for additional transports mapping
AdditionalProtocolsInfo = (RPC_PROTOCOL_INFO *) new unsigned char [
sizeof(RPC_PROTOCOL_INFO) * NumberOfValues];
if (AdditionalProtocolsInfo == 0)
{
Status = RPC_S_OUT_OF_MEMORY;
goto Cleanup;
}
AdditionalProtocols = AdditionalProtocolsInfo;
TotalAdditionalProtocols = NumberOfValues;
for (Index = 0; Index < NumberOfValues; Index++)
{
ProtseqLength = MAX_PROTSEQ_LENGTH;
IgnoreLength = MAX_ENDPOINT_LENGTH + MAX_ID_LENGTH;
RegStatus = RegEnumValueA(
RegistryKey,
Index,
(LPSTR) &Protseq,
&ProtseqLength,
0,
&Ignore,
(LPBYTE) MaxValueData,
&IgnoreLength
);
if (RegStatus == ERROR_SUCCESS)
{
//Add this to our table..
AdditionalProtocolsInfo->RpcProtocolSequence =
new unsigned char[ProtseqLength+1];
Value = (char * )&MaxValueData;
AdditionalProtocolsInfo->RpcSsEndpoint =
new unsigned char[Length = (strlen(Value) + 1)];
if (AdditionalProtocolsInfo->RpcProtocolSequence == 0
|| AdditionalProtocolsInfo->RpcSsEndpoint == 0)
{
Status = RPC_S_OUT_OF_MEMORY;
goto Cleanup;
}
RpcpMemoryCopy(
AdditionalProtocolsInfo->RpcProtocolSequence,
Protseq,
ProtseqLength+1
);
RpcpMemoryCopy(
AdditionalProtocolsInfo->RpcSsEndpoint,
Value,
Length
);
Value = Value + Length;
for (TransportId = 0;
(*Value > '0') && (*Value <= '9') && (TransportId <= 255);
Value++)
{
TransportId = TransportId * 10 + (*Value - '0');
}
AdditionalProtocolsInfo->TransportId = TransportId;
AdditionalProtocolsInfo++;
}
}
Cleanup:
RegStatus = RegCloseKey(RegistryKey);
if (Status != RPC_S_OK)
{
if (AdditionalProtocols != 0)
{
AdditionalProtocolsInfo = AdditionalProtocols;
for (Index = 0; Index < NumberOfValues; Index++)
{
if (AdditionalProtocolsInfo->RpcProtocolSequence != 0)
delete AdditionalProtocolsInfo->RpcProtocolSequence;
if (AdditionalProtocolsInfo->RpcSsEndpoint != 0)
delete AdditionalProtocolsInfo->RpcSsEndpoint;
AdditionalProtocolsInfo++;
}
delete AdditionalProtocols;
AdditionalProtocols = 0;
TotalAdditionalProtocols = 0;
}
}
return(Status);
}
RPC_STATUS
RpcGetAdditionalTransportInfo(
IN unsigned long TransportId,
OUT unsigned char PAPI * PAPI * ProtocolSequence
)
{
unsigned long i;
RPC_PROTOCOL_INFO * ProtocolInfo;
RequestGlobalMutex();
if (AdditionalProtocols == 0)
{
LoadAdditionalTransportInfo();
}
ClearGlobalMutex();
for (i = 0, ProtocolInfo = AdditionalProtocols ;
i < TotalAdditionalProtocols;
i++)
{
if (ProtocolInfo->TransportId == TransportId)
{
*ProtocolSequence = ProtocolInfo->RpcProtocolSequence;
return (RPC_S_OK);
}
ProtocolInfo ++;
}
return(RPC_S_INVALID_RPC_PROTSEQ);
}
RPC_CHAR *
LocalMapRpcProtocolSequence (
IN RPC_CHAR PAPI * RpcProtocolSequence
)
/*++
Routine Description:
We need to check the supplied protocol sequence (and module) to see
if we can map them into a transport interface dll without having to
use the registry.
Arguments:
ServerSideFlag - Supplies a flag indicating whether this protocol
sequence is to be mapped for a client or a server; a non-zero
value indicates that it is being mapped for a server.
RpcProtocolSequence - Supplies the protocol sequence which we need to
map into a transport interface dll.
Return Value:
If we successfully map the protocol sequence, then a pointer to a static
string containing the transport interface dll (name) will be returned;
the caller must duplicate the string. Otherwise, zero will be returned.
--*/
{
unsigned int Index;
for (Index = 0; Index < RpcProtseqMapLength; Index++)
{
if ( RpcpStringCompare(RpcProtocolSequence,
RpcProtocolSequenceMap[Index].RpcProtocolSequence) == 0 )
{
return((RPC_CHAR *)(RpcProtocolSequenceMap[Index].TransportInterfaceDll));
}
}
return(0);
}
RPC_STATUS
RpcGetWellKnownTransportInfo(
IN unsigned long TransportId,
OUT RPC_CHAR **PSeq
)
{
unsigned int Index;
for (Index = 0; Index < RpcProtseqMapLength; Index++)
{
if (TransportId == RpcProtocolSequenceMap[Index].TransportId)
{
*PSeq = (RPC_CHAR *)RpcProtocolSequenceMap[Index].RpcProtocolSequence;
return RPC_S_OK;
}
}
return(RPC_S_PROTSEQ_NOT_SUPPORTED);
}
RPC_STATUS
RpcConfigMapRpcProtocolSequence (
IN unsigned int ServerSideFlag,
IN RPC_CHAR PAPI * RpcProtocolSequence,
OUT RPC_CHAR * PAPI * TransportInterfaceDll
)
/*++
Routine Description:
This routine is used by the rpc protocol modules to map from an
rpc protocol sequence to the name of a transport interface dll.
Arguments:
ServerSideFlag - Supplies a flag indicating whether this protocol
sequence is to be mapped for a client or a server; a non-zero
value indicates that it is being mapped for a server.
RpcProtocolSequence - Supplies the rpc protocol sequence to map.
TransportInterfaceDll - Returns the transport support dll which
supports the requested rpc protocol sequence. This will be a
newly allocated string which the caller must free.
Return Value:
RPC_S_OK - Everything worked out fine.
RPC_S_PROTSEQ_NOT_SUPPORTED - The requested rpc protocol sequence
does not have a mapping to a transport interface dll for this
rpc protocol module.
RPC_S_OUT_OF_MEMORY - We ran out of memory trying to map the rpc
protocol sequence.
--*/
{
RPC_CHAR * TempString;
HKEY RegistryKey;
DWORD Type;
long RegStatus;
unsigned char * KeyString;
unsigned long Length;
TempString = LocalMapRpcProtocolSequence(RpcProtocolSequence);
if ( TempString != 0 )
{
*TransportInterfaceDll = new RPC_CHAR[RpcpStringLength(TempString) + 1];
if ( *TransportInterfaceDll == 0 )
{
return(RPC_S_OUT_OF_MEMORY);
}
memcpy(*TransportInterfaceDll, TempString,
(RpcpStringLength(TempString) + 1) * sizeof(RPC_CHAR));
return(RPC_S_OK);
}
KeyString = (unsigned char *) RPC_REGISTRY_PROTOCOLS;
RegStatus = RegOpenKeyExA(HKEY_LOCAL_MACHINE, (LPSTR) KeyString, 0L,
KEY_READ, &RegistryKey);
if ( RegStatus != ERROR_SUCCESS )
{
return(RPC_S_PROTSEQ_NOT_SUPPORTED);
}
*TransportInterfaceDll = new RPC_CHAR[MAX_DLLNAME_LENGTH + 1];
if ( *TransportInterfaceDll == 0 )
{
RegStatus = RegCloseKey(RegistryKey);
ASSERT( RegStatus == ERROR_SUCCESS );
return(RPC_S_OUT_OF_MEMORY);
}
Length = (MAX_DLLNAME_LENGTH + 1) * sizeof(RPC_CHAR);
RegStatus = RegQueryValueEx(RegistryKey, (const RPC_SCHAR *)RpcProtocolSequence,
0, &Type, (LPBYTE) *TransportInterfaceDll, &Length);
if ( RegStatus == ERROR_SUCCESS )
{
RegStatus = RegCloseKey(RegistryKey);
ASSERT( RegStatus == ERROR_SUCCESS );
return(RPC_S_OK);
}
RegStatus = RegCloseKey(RegistryKey);
ASSERT( RegStatus == ERROR_SUCCESS );
delete *TransportInterfaceDll;
return(RPC_S_PROTSEQ_NOT_SUPPORTED);
}
RPC_STATUS
RpcConfigInquireProtocolSequencesFromKey (
OUT RPC_PROTSEQ_VECTOR PAPI * PAPI * ProtseqVector,
unsigned char *RegistryKeyName
)
/*++
Routine Description:
This routine is used to obtain a list of the rpc protocol sequences
supported by the system using a given registry key as a reference
point.
Arguments:
ProtseqVector - Returns a vector of supported rpc protocol sequences
for this rpc protocol module.
RegistryKeyName - the path of the registry key, starting from
HKLM (the HKLM itself should not be supplied)
Return Value:
RPC_S_OK - The operation completed successfully.
RPC_S_NO_PROTSEQS - The current system configuration does not
support any rpc protocol sequences.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to inquire
the rpc protocol sequences supported by the specified rpc
protocol sequence.
--*/
{
DWORD RegStatus, Index, Ignore, MaximumValueLength;
DWORD ClassLength = 64, ProtseqLength, IgnoreLength;
BYTE IgnoreData[MAX_DLLNAME_LENGTH];
FILETIME LastWriteTime;
HKEY RegistryKey = 0;
unsigned char ClassName[64];
DWORD NumberOfValues = 0;
RegStatus = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
(LPSTR) RegistryKeyName, 0L, KEY_READ, &RegistryKey);
if ( RegStatus != ERROR_SUCCESS )
{
return(RPC_S_NO_PROTSEQS);
}
RegStatus = RegQueryInfoKeyA(RegistryKey, (LPSTR) ClassName, &ClassLength,
0, &Ignore, &Ignore, &Ignore, &NumberOfValues,
&Ignore, &MaximumValueLength, &Ignore, &LastWriteTime);
ASSERT( RegStatus == ERROR_SUCCESS );
if ( RegStatus != ERROR_SUCCESS )
{
RegStatus = RegCloseKey(RegistryKey);
ASSERT( RegStatus == ERROR_SUCCESS );
return(RPC_S_NO_PROTSEQS);
}
NumberOfValues += RpcUseAllProtseqMapLength;
*ProtseqVector = (RPC_PROTSEQ_VECTOR *) new unsigned char[
sizeof(RPC_PROTSEQ_VECTOR) + (NumberOfValues - 1)
* sizeof(RPC_CHAR *)];
if ( *ProtseqVector == 0 )
{
RegStatus = RegCloseKey(RegistryKey);
ASSERT( RegStatus == ERROR_SUCCESS );
return(RPC_S_OUT_OF_MEMORY);
}
(*ProtseqVector)->Count = (unsigned int) NumberOfValues;
for (Index = 0; Index < NumberOfValues; Index++)
{
(*ProtseqVector)->Protseq[Index] = 0;
}
for (Index = 0; Index < RpcUseAllProtseqMapLength; Index++)
{
(*ProtseqVector)->Protseq[Index] = new RPC_CHAR[MAX_PROTSEQ_LENGTH];
if ( (*ProtseqVector)->Protseq[Index] == 0 )
{
RegStatus = RegCloseKey(RegistryKey);
ASSERT( RegStatus == ERROR_SUCCESS );
RpcProtseqVectorFree(ProtseqVector);
return(RPC_S_OUT_OF_MEMORY);
}
RpcpStringCopy((*ProtseqVector)->Protseq[Index],
RpcUseAllProtseqMap[Index].RpcProtocolSequence);
}
unsigned VectorIndex = Index;
for (Index = 0; VectorIndex < NumberOfValues; Index++, VectorIndex++)
{
(*ProtseqVector)->Protseq[VectorIndex] = new RPC_CHAR[MAX_PROTSEQ_LENGTH];
if ( (*ProtseqVector)->Protseq[VectorIndex] == 0 )
{
RegStatus = RegCloseKey(RegistryKey);
ASSERT( RegStatus == ERROR_SUCCESS );
RpcProtseqVectorFree(ProtseqVector);
return(RPC_S_OUT_OF_MEMORY);
}
ProtseqLength = MAX_PROTSEQ_LENGTH;
IgnoreLength = MAX_DLLNAME_LENGTH;
RegStatus = RegEnumValue(RegistryKey, Index,
(RPC_SCHAR *)(*ProtseqVector)->Protseq[VectorIndex], &ProtseqLength,
0, &Ignore, (LPBYTE) IgnoreData, &IgnoreLength);
ASSERT( RegStatus == ERROR_SUCCESS );
if (RpcpStringCompare((RPC_SCHAR *)(*ProtseqVector)->Protseq[VectorIndex], RPC_T("ncacn_np")) == 0)
{
// ignore this named pipe value - we have to have it in the registry for
// compatibility purposes with VB, but we don't really use it
NumberOfValues --;
(*ProtseqVector)->Count --;
delete (*ProtseqVector)->Protseq[VectorIndex];
VectorIndex --;
}
}
RegStatus = RegCloseKey(RegistryKey);
ASSERT( RegStatus == ERROR_SUCCESS );
return(RPC_S_OK);
}
RPC_STATUS RpcConfigInquireStaticProtocolSequences(RPC_PROTSEQ_VECTOR **ProtseqVector)
/*++
Routine Description:
Returns a protseq vector that contains all the protseqs in the static RpcProtocolSequenceMap
map.
Arguments:
ProtseqVector - Returns a vector of supported rpc protocol sequences.
Return Value:
RPC_S_OK - The operation completed successfully.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to construct the vector.
--*/
{
int nNumberOfValues = sizeof(RpcProtocolSequenceMap) / sizeof(RpcProtocolSequenceMap[0]);
int i;
*ProtseqVector = (RPC_PROTSEQ_VECTOR *) new unsigned char[
sizeof(RPC_PROTSEQ_VECTOR) + (nNumberOfValues - 1)
* sizeof(RPC_CHAR *)];
if ( *ProtseqVector == 0 )
return(RPC_S_OUT_OF_MEMORY);
(*ProtseqVector)->Count = (unsigned int) nNumberOfValues;
for (i = 0; i < nNumberOfValues; i ++)
{
(*ProtseqVector)->Protseq[i] = NULL;
}
for (i = 0; i < nNumberOfValues; i ++)
{
(*ProtseqVector)->Protseq[i] = new RPC_CHAR[MAX_PROTSEQ_LENGTH];
if ( (*ProtseqVector)->Protseq[i] == 0 )
{
RpcProtseqVectorFree(ProtseqVector);
return(RPC_S_OUT_OF_MEMORY);
}
RpcpStringCopy((*ProtseqVector)->Protseq[i],
RpcProtocolSequenceMap[i].RpcProtocolSequence);
}
return RPC_S_OK;
}
int MarkDuplicateEntries(IN RPC_PROTSEQ_VECTOR *ProtseqVector1,
IN int nVector1CurrentPos,
IN RPC_PROTSEQ_VECTOR *ProtseqVector2 OPTIONAL,
IN OUT UCHAR *pfDuplicates1,
IN OUT UCHAR *pfDuplicates2)
/*++
Routine Description:
This routine is tightly coupled with RpcConfigInquireProtocolSequences.
If the current element is already marked as duplicate by previous
run of this function, we directly return 1. If not,
it checks whether the current element is duplicate of any element
starting with the nVetcor1StartingPos from the first vector, and
going through the whole second vector if it is there, and marking
all duplicates of the current element as such. Then 0 is returned.
If the second vector is NULL, the pfDuplicates2 must be NULL also. This
means that there is one vector only, and its data are passed in
in RpcProtseqVector1 and in pfDuplicates1.
Arguments:
RpcProtseqVector1 - the first vector
nVector1CurrentPos - the current position from the first vector
RpcProtseqVector2 - the second vector. This argument may be null
pfDuplicates1 - the array of duplicate flags for the first vector
pfDuplicates2 - the array of duplicate flags for the second vector. If
second vector is NULL, must be NULL also.
Return Value:
1 - the current element is a duplicate of an element that we
encountered in a previous run of this function.
0 - the current element is unique in both vectors
--*/
{
int i;
RPC_CHAR *pszCurrentElement;
ASSERT(nVector1CurrentPos < (int)ProtseqVector1->Count);
if (pfDuplicates1[nVector1CurrentPos])
return 1;
pszCurrentElement = ProtseqVector1->Protseq[nVector1CurrentPos];
for (i = nVector1CurrentPos + 1; i < (int)ProtseqVector1->Count; i ++)
{
if (RpcpStringCompare(pszCurrentElement,
ProtseqVector1->Protseq[i]) == 0)
{
pfDuplicates1[i] = TRUE;
}
}
if (ProtseqVector2)
{
ASSERT(pfDuplicates2 != NULL);
for (i = 0; i < (int)ProtseqVector2->Count; i ++)
{
if (RpcpStringCompare(pszCurrentElement,
ProtseqVector2->Protseq[i]) == 0)
{
pfDuplicates2[i] = TRUE;
}
}
}
else
{
ASSERT(pfDuplicates2 == NULL);
}
return 0;
}
RPC_STATUS
MergeProtseqVectors (IN OUT RPC_PROTSEQ_VECTOR *ProtseqVector1,
IN OUT RPC_PROTSEQ_VECTOR *ProtseqVector2 OPTIONAL,
OUT RPC_PROTSEQ_VECTOR **ProtseqVector
)
/*++
Routine Description:
This routine takes two protseq vectors, and in the OUT argument ProtseqVector
returns the resulting vector, which is a union of the two IN
vectors. Successful or not, the input vectors will be freed on exit.
Arguments:
ProtseqVector1 - the first vector
ProtseqVector2 - the second vector. This argument may be null in which case the
output vector is simply the first vector.
ProtseqVector - the resulting union vector. If the return value from the function
is not RPC_S_OK, the out parameter is undefined and should not be used by caller.
Return Value:
RPC_S_OK - success. The ProtseqVector argument contains the resulting vector.
error code - the cause of the error.
--*/
{
unsigned char *pfDuplicate1;
unsigned char *pfDuplicate2;
int i, j;
int nDuplicateElements;
int nCurrentElement;
int nUniqueElements;
// compare basically each with each
// construct arrays in which we will mark each duplicate element
// if it is such
pfDuplicate1 = (unsigned char *)alloca(ProtseqVector1->Count);
if (ProtseqVector2)
pfDuplicate2 = (unsigned char *)alloca(ProtseqVector2->Count);
else
pfDuplicate2 = NULL;
// all elements are presumed to be unique unless proven otherwise
memset(pfDuplicate1, 0, ProtseqVector1->Count);
if (ProtseqVector2)
memset(pfDuplicate2, 0, ProtseqVector2->Count);
nDuplicateElements = 0;
// do compare each with each
// test the first vector for uniqueness
for (i = 0; i < (int)ProtseqVector1->Count; i ++)
{
nDuplicateElements += MarkDuplicateEntries(ProtseqVector1, i,
ProtseqVector2, pfDuplicate1, pfDuplicate2);
}
if (ProtseqVector2)
{
// test the second vector for uniqueness
for (i = 0; i < (int)ProtseqVector2->Count; i ++)
{
nDuplicateElements += MarkDuplicateEntries(ProtseqVector2, i,
NULL, pfDuplicate2, NULL);
}
}
// here we must move the unique elements to a new vector
// first, calculate the length of the new vector
nUniqueElements = ProtseqVector1->Count - nDuplicateElements;
if (ProtseqVector2)
nUniqueElements += ProtseqVector2->Count;
// second, alloc the new vector
*ProtseqVector = (RPC_PROTSEQ_VECTOR *) new unsigned char[
sizeof(RPC_PROTSEQ_VECTOR) +
(nUniqueElements - 1) * sizeof(RPC_CHAR *)];
if (*ProtseqVector == NULL)
{
RpcProtseqVectorFree(&ProtseqVector1);
if (ProtseqVector2)
RpcProtseqVectorFree(&ProtseqVector2);
return RPC_S_OUT_OF_MEMORY;
}
// set the count of the union vector
(*ProtseqVector)->Count = nUniqueElements;
nCurrentElement = 0; // counts the current element in the union
// vector
for (i = 0; i < (int)ProtseqVector1->Count; i ++)
{
if (!pfDuplicate1[i])
{
(*ProtseqVector)->Protseq[nCurrentElement] =
ProtseqVector1->Protseq[i];
nCurrentElement ++;
// save the string from deletion
ProtseqVector1->Protseq[i] = NULL;
}
}
if (ProtseqVector2)
{
for (i = 0; i < (int)ProtseqVector2->Count; i ++)
{
if (!pfDuplicate2[i])
{
(*ProtseqVector)->Protseq[nCurrentElement] =
ProtseqVector2->Protseq[i];
nCurrentElement ++;
// save the string from deletion
ProtseqVector2->Protseq[i] = NULL;
}
}
}
// we don't need the original vectors anymore - delete them
RpcProtseqVectorFree(&ProtseqVector1);
if (ProtseqVector2)
RpcProtseqVectorFree(&ProtseqVector2);
return RPC_S_OK;
}
RPC_STATUS
RpcConfigInquireProtocolSequences (
IN BOOL fGetAllProtseqs,
OUT RPC_PROTSEQ_VECTOR PAPI * PAPI * ProtseqVector1
)
/*++
Routine Description:
This routine is used to obtain a list of the rpc protocol sequences
supported by the system.
Arguments:
fGetAllProtseqs - if TRUE, all protseqs known will be returned. If FALSE,
only the protseqs currently installed will be returned.
ProtseqVector - Returns a vector of supported rpc protocol sequences
for this rpc protocol module.
Return Value:
RPC_S_OK - The operation completed successfully.
RPC_S_NO_PROTSEQS - The current system configuration does not
support any rpc protocol sequences.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to inquire
the rpc protocol sequences supported by rpc.
--*/
{
RPC_STATUS RpcStatus1;
RPC_STATUS RpcStatus2;
RPC_PROTSEQ_VECTOR *ProtseqVector2 = NULL;
RPC_PROTSEQ_VECTOR *ProtseqVector;
if (fGetAllProtseqs)
{
RpcStatus2 = RpcConfigInquireStaticProtocolSequences(&ProtseqVector2);
if (RpcStatus2 != RPC_S_OK)
return RpcStatus2;
}
// under NT, failure to query the registry vector is fatal. Under Win98, querying
// this registry vector is optional, and if we fail, we have to continue gathering the
// vector from other sources.
RpcStatus1 = RpcConfigInquireProtocolSequencesFromKey(
ProtseqVector1, (unsigned char *)RPC_REGISTRY_PROTOCOLS);
if (RpcStatus1 != RPC_S_OK)
{
RpcProtseqVectorFree(&ProtseqVector2);
return RpcStatus1;
}
if (fGetAllProtseqs)
{
// Merge the static vector and the one from the registry
RpcStatus1 = MergeProtseqVectors(*ProtseqVector1, ProtseqVector2, &ProtseqVector);
if (RpcStatus1 != RPC_S_OK)
{
return RpcStatus1;
}
*ProtseqVector1 = ProtseqVector;
}
return RpcStatus1;
}
// N.B. This enumration must agree with the values
// in system.adm
typedef enum tagStateInformationPolicyValues
{
sipvNone,
sipvAuto1,
sipvAuto2,
sipvServer,
sipvFull
} StateInformationPolicyValues;
// N.B. This enumration must agree with the values
// in system.adm
typedef enum tagEEInfoPolicyValues
{
eeipvOff,
eeipvOnWithExceptions,
eeipvOffWithExceptions,
eeipvOn
} EEInfoPolicyValues;
void
SetAutoPolicySettings(
StateInformationPolicyValues PolicyValue
)
/*++
Routine Description:
This routine sets the state information maintenance to the appropriate
level of Auto, depending on machine capacity.
Arguments:
PolicyValue - sipvAuto1 or sipvAuto2
Return Value:
RPC_S_OK - The operation completed successfully.
other RPC_S_* - error
--*/
{
NT_PRODUCT_TYPE ProductType;
BOOL fNeedServer;
ULONG_PTR MinMemoryNeeded;
MEMORYSTATUSEX MemoryStatus;
BOOL fResult;
ASSERT((PolicyValue == sipvAuto1) || (PolicyValue == sipvAuto2));
// client side debug info is FALSE by default - no need to
// set it explicitly
// see what we have
// RtlGetNtProductType always returns valid ProductType
// It may be incorrect during GUI mode setup, but it will
// be valid
(VOID) RtlGetNtProductType(&ProductType);
MemoryStatus.dwLength = sizeof(MemoryStatus);
fResult = GlobalMemoryStatusEx(&MemoryStatus);
ASSERT(fResult);
// see what we have been asked for
if (PolicyValue == sipvAuto1)
{
fNeedServer = FALSE;
MinMemoryNeeded = 64 * 1024 * 1024; // 64MB of RAM
}
else
{
ASSERT (PolicyValue == sipvAuto2);
fNeedServer = TRUE;
MinMemoryNeeded = 127 * 1024 * 1024; // 127MB of RAM
}
// if we need server, but this is workstation, no state info
if (fNeedServer && (ProductType == NtProductWinNt))
{
g_fServerSideDebugInfoEnabled = FALSE;
return;
}
// if we have less physical memory than the one we need,
// no state info
if (MemoryStatus.ullTotalPhys < (ULONGLONG) MinMemoryNeeded)
{
g_fServerSideDebugInfoEnabled = FALSE;
return;
}
g_fServerSideDebugInfoEnabled = TRUE;
}
typedef enum tagExceptionListParserState
{
elpsOutsideOfQuotes,
elpsInsideQuotes,
elpsReadingWhitespace,
elpsReadingCharacter
} ExceptionListParserState;
BOOL
DoesThisProcessCmdLineStartWithThisString (
IN LPWSTR CmdLine,
IN LPWSTR CmdLineStart
)
/*++
Routine Description:
Checks if the process name starts with the string given
in CmdLineStart
Arguments:
CmdLine - the process command line with path name stripped
CmdLineStart - the patter to match against
Return Value:
non-zero - there is a match
FALSE - there is no match
--*/
{
int CmdLineLength = RpcpStringLength(CmdLine);
int CmdLineStartLength = RpcpStringLength(CmdLineStart);
if (CmdLineLength >= CmdLineStartLength)
{
if (RpcpStringNCompare(CmdLine, CmdLineStart, CmdLineStartLength) == 0)
return TRUE;
}
return FALSE;
}
typedef enum tagExceptionListCharacterTypes
{
elctQuotes,
elctCharacter,
elctWhitespace
} ExceptionListCharacterTypes;
inline ExceptionListCharacterTypes
GetCharacterType (
RPC_CHAR Character
)
{
if (Character == '"')
return elctQuotes;
if (Character == ' ')
return elctWhitespace;
return elctCharacter;
}
RPC_STATUS
IsThisProcessAnException (
IN HKEY RegistryKey,
BOOL *fThisProcessIsException
)
/*++
Routine Description:
Checks whether the current process is in the exceptions list as
specified in the ExtErrorInfoExceptions registry key
Arguments:
RegistryKey - an open key to RPC_POLICY_SETTINGS
fThisProcessIsException - on output non-zero if this process is
an exception and FALSE otherwise
Return Value:
RPC_S_OK or RPC_S_* error
--*/
{
DWORD RegStatus;
RPC_CHAR *Buffer = NULL;
DWORD Type;
DWORD Size = 0;
int Retries = 5;
int State;
RPC_CHAR *CurrentPos;
RPC_CHAR *CurrentString;
RPC_CHAR *CommandLine;
RPC_CHAR *LastBackslash;
BOOL fIsSubstring;
*fThisProcessIsException = FALSE;
while (Retries > 0)
{
RegStatus = RegQueryValueExW(
RegistryKey,
L"ExtErrorInfoExceptions",
0,
&Type,
(LPBYTE) Buffer,
&Size
);
if ( (RegStatus != ERROR_SUCCESS) && (RegStatus != ERROR_MORE_DATA) )
{
if (RegStatus == ERROR_FILE_NOT_FOUND)
RegStatus = RPC_S_OK;
else
RegStatus = RPC_S_OUT_OF_MEMORY;
goto CleanupAndReturn;
}
else
{
if ((Buffer == NULL) || (RegStatus == ERROR_MORE_DATA))
{
if (Buffer)
delete Buffer;
Buffer = new RPC_CHAR[Size];
if (Buffer == NULL)
{
RegStatus = RPC_S_OUT_OF_MEMORY;
goto CleanupAndReturn;
}
continue;
}
if (Type != REG_SZ)
{
RegStatus = RPC_S_INTERNAL_ERROR;
goto CleanupAndReturn;
}
ASSERT(RegStatus == RPC_S_OK);
CommandLine = GetCommandLine();
LastBackslash = wcsrchr(CommandLine, '\\');
if (LastBackslash != NULL)
CommandLine = LastBackslash + 1;
// here, Buffer contains the exception string
// The format of the exception string is:
// "cmd_line_start" "cmd_line_start" ...
// If there is only one cmd_line_start, it doesn't have to be in double quotes
State = elpsOutsideOfQuotes;
CurrentPos = Buffer;
CurrentString = NULL;
while (*CurrentPos != 0)
{
switch (State)
{
case elpsOutsideOfQuotes:
switch (GetCharacterType(*CurrentPos))
{
case elctQuotes:
CurrentString = CurrentPos;
State = elpsInsideQuotes;
break;
case elctCharacter:
CurrentString = CurrentPos;
State = elpsReadingCharacter;
break;
case elctWhitespace:
State = elpsReadingWhitespace;
break;
default:
ASSERT(0);
}
break;
case elpsReadingCharacter:
switch (GetCharacterType(*CurrentPos))
{
case elctQuotes:
*CurrentPos = 0;
fIsSubstring = DoesThisProcessCmdLineStartWithThisString(
CommandLine, CurrentString);
if (fIsSubstring)
{
*fThisProcessIsException = TRUE;
goto CleanupAndReturn;
}
CurrentString = CurrentPos + 1;
State = elpsReadingCharacter;
break;
case elctWhitespace:
*CurrentPos = 0;
fIsSubstring = DoesThisProcessCmdLineStartWithThisString(
CommandLine, CurrentString);
if (fIsSubstring)
{
*fThisProcessIsException = TRUE;
goto CleanupAndReturn;
}
State = elpsReadingCharacter;
break;
// default:
// can be elpsReadingCharacter
}
break;
case elpsReadingWhitespace:
switch (GetCharacterType(*CurrentPos))
{
case elctQuotes:
CurrentString = CurrentPos + 1;
State = elpsInsideQuotes;
break;
case elctCharacter:
CurrentString = CurrentPos;
State = elpsReadingCharacter;
break;
// default:
// can be elctWhitespace
}
break;
case elpsInsideQuotes:
switch (GetCharacterType(*CurrentPos))
{
case elctQuotes:
*CurrentPos = 0;
fIsSubstring = DoesThisProcessCmdLineStartWithThisString(
CommandLine, CurrentString);
if (fIsSubstring)
{
*fThisProcessIsException = TRUE;
goto CleanupAndReturn;
}
State = elpsOutsideOfQuotes;
break;
//default:
// can be elctCharacter or elctWhitespace
}
break;
default:
ASSERT(0);
}
CurrentPos ++;
}
if (CurrentString)
{
fIsSubstring = DoesThisProcessCmdLineStartWithThisString(
CommandLine, CurrentString);
if (fIsSubstring)
{
*fThisProcessIsException = TRUE;
goto CleanupAndReturn;
}
}
break;
}
Retries --;
}
CleanupAndReturn:
if (Buffer)
delete Buffer;
if (Retries == 0)
RegStatus = RPC_S_INTERNAL_ERROR;
return RegStatus;
}
RPC_STATUS ReadPolicySettings(void)
/*++
Routine Description:
Reads the policy settings for RPC and sets the appropriate global
variables.
Arguments:
void
Return Value:
RPC_S_OK or RPC_S_* error
--*/
{
HKEY RegistryKey;
DWORD RegStatus;
DWORD Result;
DWORD Type;
DWORD DwordSize = sizeof(DWORD);
BOOL ThisProcessIsException;
RegStatus = RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
(LPWSTR) RPC_POLICY_SETTINGS,
0L, //Reserved
KEY_READ,
&RegistryKey
);
if ( RegStatus != ERROR_SUCCESS )
{
if (RegStatus == ERROR_FILE_NOT_FOUND)
{
SetAutoPolicySettings(sipvAuto2);
return RPC_S_OK;
}
return RPC_S_OUT_OF_MEMORY;
}
RegStatus = RegQueryValueExW(
RegistryKey,
L"StateInformation",
0,
&Type,
(LPBYTE) &Result,
&DwordSize
);
if ( RegStatus != ERROR_SUCCESS )
{
if (RegStatus == ERROR_FILE_NOT_FOUND)
{
SetAutoPolicySettings(sipvAuto2);
RegStatus = RPC_S_OK;
}
else
{
RegStatus = RPC_S_OUT_OF_MEMORY;
goto CleanupAndReturn;
}
}
else
{
if (Type != REG_DWORD)
{
RegStatus = RPC_S_INTERNAL_ERROR;
goto CleanupAndReturn;
}
ASSERT(RegStatus == RPC_S_OK);
switch (Result)
{
case sipvNone:
// nothing to do - the client/server DebugInfoEnabled values
// are off by default
break;
case sipvAuto1:
case sipvAuto2:
SetAutoPolicySettings((StateInformationPolicyValues)Result);
break;
case sipvServer:
g_fServerSideDebugInfoEnabled = TRUE;
break;
case sipvFull:
g_fServerSideDebugInfoEnabled = TRUE;
g_fClientSideDebugInfoEnabled = TRUE;
break;
default:
RegStatus = RPC_S_INTERNAL_ERROR;
goto CleanupAndReturn;
}
}
RegStatus = RegQueryValueExW(
RegistryKey,
L"ExtErrorInformation",
0,
&Type,
(LPBYTE) &Result,
&DwordSize
);
if ( RegStatus != ERROR_SUCCESS )
{
if (RegStatus == ERROR_FILE_NOT_FOUND)
{
RegStatus = RPC_S_OK;
}
else
{
RegStatus = RPC_S_OUT_OF_MEMORY;
goto CleanupAndReturn;
}
}
else
{
if (Type != REG_DWORD)
{
RegStatus = RPC_S_INTERNAL_ERROR;
goto CleanupAndReturn;
}
ASSERT(RegStatus == RPC_S_OK);
switch (Result)
{
case eeipvOff:
// nothing to do - the g_fSendEEInfo is already false
break;
case eeipvOnWithExceptions:
RegStatus = IsThisProcessAnException(RegistryKey,
&ThisProcessIsException);
if ((RegStatus != RPC_S_OK) || (ThisProcessIsException == FALSE))
g_fSendEEInfo = TRUE;
break;
case eeipvOffWithExceptions:
RegStatus = IsThisProcessAnException(RegistryKey,
&ThisProcessIsException);
if ((RegStatus == RPC_S_OK) && (ThisProcessIsException == TRUE))
g_fSendEEInfo = TRUE;
break;
case eeipvOn:
g_fSendEEInfo = TRUE;
break;
default:
RegStatus = RPC_S_INTERNAL_ERROR;
goto CleanupAndReturn;
}
}
CleanupAndReturn:
RegCloseKey(RegistryKey);
return RegStatus;
}
RPCRTAPI
RPC_STATUS
RPC_ENTRY
I_RpcSystemFunction001 (
IN SystemFunction001Commands FunctionCode,
IN void *InData,
OUT void *OutData
)
/*++
Routine Description:
Test hook.
Arguments:
FunctionCode - which test function to perform
InData - input data from the test function
OutData - output data from the test function
Return Value:
RPC_S_OK or RPC_S_* error
--*/
{
THREAD *Thread;
InitializeIfNecessary();
Thread = ThreadSelf();
if (!Thread)
return RPC_S_OUT_OF_MEMORY;
RpcpPurgeEEInfoFromThreadIfNecessary(Thread);
switch (FunctionCode)
{
case sf001cHttpSetInChannelTarget:
case sf001cHttpSetOutChannelTarget:
return HTTP2TestHook (FunctionCode,
InData,
OutData
);
break;
default:
return RPC_S_CANNOT_SUPPORT;
}
return RPC_S_OK;
}
#ifdef WINNT35_UUIDS
unsigned long
SomeLongValue (
)
/*++
Routine Description:
This routine, SomeShortValue, AnotherShortValue, and SomeCharacterValue
are used to generate the fields of a GUID if we can not determine
the network address from the network card (so we can generate a
UUID). These routines must generate some pseudo random values
based on the current time and/or the time since boot as well as the
current process and thread.
For the long value, we will use the current thread identifier and
current process identifier bitwise exclusive ored together.
For the two short values, we use the low part of the time field
(which is long, which we split into two values).
Finally, for the character value, we use a constant.
Return Value:
An unsigned long value will be returned.
--*/
{
TEB * CurrentTeb;
CurrentTeb = NtCurrentTeb();
return(((unsigned long) CurrentTeb->ClientId.UniqueThread)
^ ((unsigned long) CurrentTeb->ClientId.UniqueProcess));
}
unsigned short
SomeShortValue (
)
/*++
See SomeLongValue.
--*/
{
LARGE_INTEGER SystemTime;
for (;;)
{
NtQuerySystemTime(&SystemTime);
if (ThreadSelf()->TimeLow != SystemTime.LowPart)
break;
PauseExecution(1L);
}
ThreadSelf()->TimeLow = SystemTime.LowPart;
return((unsigned short) SystemTime.LowPart);
}
unsigned short
AnotherShortValue (
)
/*++
See SomeLongValue.
--*/
{
return((unsigned short) (ThreadSelf()->TimeLow >> 16));
}
unsigned char
SomeCharacterValue (
)
/*++
See SomeLongValue.
--*/
{
return(0x69);
}
#endif WINNT35_UUIDS
typedef struct {
RPC_STATUS RpcStatus;
long NtStatus;
} STATUS_MAPPING;
static const STATUS_MAPPING StatusMap[] =
{
{ RPC_S_OK, STATUS_SUCCESS },
{ RPC_S_INVALID_STRING_BINDING, RPC_NT_INVALID_STRING_BINDING },
{ RPC_S_WRONG_KIND_OF_BINDING, RPC_NT_WRONG_KIND_OF_BINDING },
{ RPC_S_INVALID_BINDING, RPC_NT_INVALID_BINDING },
{ RPC_S_PROTSEQ_NOT_SUPPORTED, RPC_NT_PROTSEQ_NOT_SUPPORTED },
{ RPC_S_INVALID_RPC_PROTSEQ, RPC_NT_INVALID_RPC_PROTSEQ },
{ RPC_S_INVALID_STRING_UUID, RPC_NT_INVALID_STRING_UUID },
{ RPC_S_INVALID_ENDPOINT_FORMAT, RPC_NT_INVALID_ENDPOINT_FORMAT },
{ RPC_S_INVALID_NET_ADDR, RPC_NT_INVALID_NET_ADDR },
{ RPC_S_NO_ENDPOINT_FOUND, RPC_NT_NO_ENDPOINT_FOUND },
{ RPC_S_INVALID_TIMEOUT, RPC_NT_INVALID_TIMEOUT },
{ RPC_S_OBJECT_NOT_FOUND, RPC_NT_OBJECT_NOT_FOUND },
{ RPC_S_ALREADY_REGISTERED, RPC_NT_ALREADY_REGISTERED },
{ RPC_S_TYPE_ALREADY_REGISTERED, RPC_NT_TYPE_ALREADY_REGISTERED },
{ RPC_S_ALREADY_LISTENING, RPC_NT_ALREADY_LISTENING },
{ RPC_S_NO_PROTSEQS_REGISTERED, RPC_NT_NO_PROTSEQS_REGISTERED },
{ RPC_S_NOT_LISTENING, RPC_NT_NOT_LISTENING },
{ RPC_S_UNKNOWN_MGR_TYPE, RPC_NT_UNKNOWN_MGR_TYPE },
{ RPC_S_UNKNOWN_IF, RPC_NT_UNKNOWN_IF },
{ RPC_S_NO_BINDINGS, RPC_NT_NO_BINDINGS },
{ RPC_S_NO_MORE_BINDINGS, RPC_NT_NO_MORE_BINDINGS },
{ RPC_S_NO_PROTSEQS, RPC_NT_NO_PROTSEQS },
{ RPC_S_CANT_CREATE_ENDPOINT, RPC_NT_CANT_CREATE_ENDPOINT },
{ RPC_S_OUT_OF_RESOURCES, RPC_NT_OUT_OF_RESOURCES },
{ RPC_S_SERVER_UNAVAILABLE, RPC_NT_SERVER_UNAVAILABLE },
{ RPC_S_SERVER_TOO_BUSY, RPC_NT_SERVER_TOO_BUSY },
{ RPC_S_INVALID_NETWORK_OPTIONS, RPC_NT_INVALID_NETWORK_OPTIONS },
{ RPC_S_NO_CALL_ACTIVE, RPC_NT_NO_CALL_ACTIVE },
{ RPC_S_CALL_FAILED, RPC_NT_CALL_FAILED },
{ RPC_S_CALL_CANCELLED, RPC_NT_CALL_CANCELLED },
{ RPC_S_CALL_FAILED_DNE, RPC_NT_CALL_FAILED_DNE },
{ RPC_S_PROTOCOL_ERROR, RPC_NT_PROTOCOL_ERROR },
{ RPC_S_UNSUPPORTED_TRANS_SYN, RPC_NT_UNSUPPORTED_TRANS_SYN },
{ RPC_S_SERVER_OUT_OF_MEMORY, STATUS_INSUFF_SERVER_RESOURCES },
{ RPC_S_UNSUPPORTED_TYPE, RPC_NT_UNSUPPORTED_TYPE },
{ RPC_S_INVALID_TAG, RPC_NT_INVALID_TAG },
{ RPC_S_INVALID_BOUND, RPC_NT_INVALID_BOUND },
{ RPC_S_NO_ENTRY_NAME, RPC_NT_NO_ENTRY_NAME },
{ RPC_S_INVALID_NAME_SYNTAX, RPC_NT_INVALID_NAME_SYNTAX },
{ RPC_S_UNSUPPORTED_NAME_SYNTAX, RPC_NT_UNSUPPORTED_NAME_SYNTAX },
{ RPC_S_UUID_NO_ADDRESS, RPC_NT_UUID_NO_ADDRESS },
{ RPC_S_DUPLICATE_ENDPOINT, RPC_NT_DUPLICATE_ENDPOINT },
{ RPC_S_UNKNOWN_AUTHN_TYPE, RPC_NT_UNKNOWN_AUTHN_TYPE },
{ RPC_S_MAX_CALLS_TOO_SMALL, RPC_NT_MAX_CALLS_TOO_SMALL },
{ RPC_S_STRING_TOO_LONG, RPC_NT_STRING_TOO_LONG },
{ RPC_S_PROTSEQ_NOT_FOUND, RPC_NT_PROTSEQ_NOT_FOUND },
{ RPC_S_PROCNUM_OUT_OF_RANGE, RPC_NT_PROCNUM_OUT_OF_RANGE },
{ RPC_S_BINDING_HAS_NO_AUTH, RPC_NT_BINDING_HAS_NO_AUTH },
{ RPC_S_UNKNOWN_AUTHN_SERVICE, RPC_NT_UNKNOWN_AUTHN_SERVICE },
{ RPC_S_UNKNOWN_AUTHN_LEVEL, RPC_NT_UNKNOWN_AUTHN_LEVEL },
{ RPC_S_INVALID_AUTH_IDENTITY, RPC_NT_INVALID_AUTH_IDENTITY },
{ RPC_S_UNKNOWN_AUTHZ_SERVICE, RPC_NT_UNKNOWN_AUTHZ_SERVICE },
{ EPT_S_INVALID_ENTRY, EPT_NT_INVALID_ENTRY },
{ EPT_S_CANT_PERFORM_OP, EPT_NT_CANT_PERFORM_OP },
{ EPT_S_NOT_REGISTERED, EPT_NT_NOT_REGISTERED },
{ RPC_S_NOTHING_TO_EXPORT, RPC_NT_NOTHING_TO_EXPORT },
{ RPC_S_INCOMPLETE_NAME, RPC_NT_INCOMPLETE_NAME },
{ RPC_S_INVALID_VERS_OPTION, RPC_NT_INVALID_VERS_OPTION },
{ RPC_S_NO_MORE_MEMBERS, RPC_NT_NO_MORE_MEMBERS },
{ RPC_S_NOT_ALL_OBJS_UNEXPORTED, RPC_NT_NOT_ALL_OBJS_UNEXPORTED },
{ RPC_S_INTERFACE_NOT_FOUND, RPC_NT_INTERFACE_NOT_FOUND },
{ RPC_S_ENTRY_ALREADY_EXISTS, RPC_NT_ENTRY_ALREADY_EXISTS },
{ RPC_S_ENTRY_NOT_FOUND, RPC_NT_ENTRY_NOT_FOUND },
{ RPC_S_NAME_SERVICE_UNAVAILABLE, RPC_NT_NAME_SERVICE_UNAVAILABLE },
{ RPC_S_INVALID_NAF_ID, RPC_NT_INVALID_NAF_ID },
{ RPC_S_CANNOT_SUPPORT, RPC_NT_CANNOT_SUPPORT },
{ RPC_S_NO_CONTEXT_AVAILABLE, RPC_NT_NO_CONTEXT_AVAILABLE },
{ RPC_S_INTERNAL_ERROR, RPC_NT_INTERNAL_ERROR },
{ RPC_S_ZERO_DIVIDE, RPC_NT_ZERO_DIVIDE },
{ RPC_S_ADDRESS_ERROR, RPC_NT_ADDRESS_ERROR },
{ RPC_S_FP_DIV_ZERO, RPC_NT_FP_DIV_ZERO },
{ RPC_S_FP_UNDERFLOW, RPC_NT_FP_UNDERFLOW },
{ RPC_S_FP_OVERFLOW, RPC_NT_FP_OVERFLOW },
{ RPC_X_NO_MORE_ENTRIES, RPC_NT_NO_MORE_ENTRIES },
{ RPC_X_SS_CHAR_TRANS_OPEN_FAIL, RPC_NT_SS_CHAR_TRANS_OPEN_FAIL },
{ RPC_X_SS_CHAR_TRANS_SHORT_FILE, RPC_NT_SS_CHAR_TRANS_SHORT_FILE },
{ RPC_X_SS_IN_NULL_CONTEXT, RPC_NT_SS_IN_NULL_CONTEXT },
{ RPC_X_SS_CONTEXT_MISMATCH, RPC_NT_SS_CONTEXT_MISMATCH },
{ RPC_X_SS_CONTEXT_DAMAGED, RPC_NT_SS_CONTEXT_DAMAGED },
{ RPC_X_SS_HANDLES_MISMATCH, RPC_NT_SS_HANDLES_MISMATCH },
{ RPC_X_SS_CANNOT_GET_CALL_HANDLE, RPC_NT_SS_CANNOT_GET_CALL_HANDLE },
{ RPC_X_NULL_REF_POINTER, RPC_NT_NULL_REF_POINTER },
{ RPC_X_ENUM_VALUE_OUT_OF_RANGE, RPC_NT_ENUM_VALUE_OUT_OF_RANGE },
{ RPC_X_BYTE_COUNT_TOO_SMALL, RPC_NT_BYTE_COUNT_TOO_SMALL },
{ RPC_X_BAD_STUB_DATA, RPC_NT_BAD_STUB_DATA },
{ ERROR_INVALID_PARAMETER, STATUS_INVALID_PARAMETER },
{ ERROR_OUTOFMEMORY, STATUS_NO_MEMORY },
{ ERROR_MAX_THRDS_REACHED, STATUS_NO_MEMORY },
{ ERROR_INSUFFICIENT_BUFFER, STATUS_BUFFER_TOO_SMALL },
{ ERROR_INVALID_SECURITY_DESCR, STATUS_INVALID_SECURITY_DESCR },
{ ERROR_ACCESS_DENIED, STATUS_ACCESS_DENIED },
{ ERROR_NOACCESS, STATUS_ACCESS_VIOLATION },
{ RPC_S_CALL_IN_PROGRESS, RPC_NT_CALL_IN_PROGRESS },
{ RPC_S_GROUP_MEMBER_NOT_FOUND, RPC_NT_GROUP_MEMBER_NOT_FOUND },
{ EPT_S_CANT_CREATE, EPT_NT_CANT_CREATE },
{ RPC_S_INVALID_OBJECT, RPC_NT_INVALID_OBJECT },
{ RPC_S_INVALID_ASYNC_HANDLE, RPC_NT_INVALID_ASYNC_HANDLE },
{ RPC_S_INVALID_ASYNC_CALL, RPC_NT_INVALID_ASYNC_CALL },
{ RPC_X_PIPE_CLOSED, RPC_NT_PIPE_CLOSED },
{ RPC_X_PIPE_EMPTY, RPC_NT_PIPE_EMPTY },
{ RPC_X_PIPE_DISCIPLINE_ERROR, RPC_NT_PIPE_DISCIPLINE_ERROR }
};
long RPC_ENTRY
I_RpcMapWin32Status (
IN RPC_STATUS Status
)
/*++
Routine Description:
This routine maps a WIN32 RPC status code into an NT RPC status code.
Arguments:
Status - Supplies the WIN32 RPC status code to be mapped.
Return Value:
The NT RPC status code corresponding to the WIN32 RPC status code
will be returned.
--*/
{
register int i;
for(i = 0; i < sizeof(StatusMap)/sizeof(STATUS_MAPPING); i++)
{
if (StatusMap[i].RpcStatus == Status)
{
return(StatusMap[i].NtStatus);
}
}
return(Status);
}