Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

857 lines
21 KiB

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
miscnt.cxx
Abstract:
This file contains NT specific implementations of miscellaneous
routines.
Author:
Michael Montague (mikemon) 25-Nov-1991
Revision History:
--*/
#include <memory.h>
#include <sysinc.h>
#include <rpc.h>
#include <rpctran.h>
#include <util.hxx>
#include <rpccfg.h>
#include <mutex.hxx>
#include "threads.hxx"
#define MAX_PRINTF_LEN 1024
char
__pure_virtual_called()
{
#ifdef DEBUGRPC
PrintToDebugger("RPCRT4: Pure Virtual Called\n");
#endif
return (0);
}
#define RPC_REGISTRY_CLIENT_PROTOCOLS \
"Software\\Microsoft\\Rpc\\ClientProtocols"
#define RPC_REGISTRY_SERVER_PROTOCOLS \
"Software\\Microsoft\\Rpc\\ServerProtocols"
#define RPC_REGISTRY_PROTOCOL_IDS \
"Software\\Microsoft\\Rpc\\AdditionalProtocols"
#define MAX_PROTSEQ_LENGTH 32
#define MAX_ENDPOINT_LENGTH 128
#define MAX_ID_LENGTH 6
#define MAX_DLL_NAME 128
typedef struct
{
RPC_CHAR * RpcProtocolSequence;
RPC_CHAR * TransportInterfaceDll;
} RPC_PROTOCOL_SEQUENCE_MAP;
RPC_PROTOCOL_SEQUENCE_MAP ServerRpcProtocolSequenceMap[] =
{
{
(RPC_CHAR *)"ncalrpc",
(RPC_CHAR *)0
}
};
RPC_PROTOCOL_SEQUENCE_MAP ClientRpcProtocolSequenceMap[] =
{
{ (RPC_CHAR *)"ncalrpc", (RPC_CHAR *)0 },
{ (RPC_CHAR *)"ncacn_np", (RPC_CHAR *)"rpcltc1.dll" }
};
typedef struct
{
unsigned char * RpcProtocolSequence;
unsigned char * RpcSsEndpoint;
unsigned long TransportId;
} RPC_PROTOCOL_INFO;
RPC_PROTOCOL_INFO StaticProtocolMapping[] =
{
{
(unsigned char *)"ncacn_np",
(unsigned char *)"\\pipe\\epmapper",
0x0F
}
};
RPC_PROTOCOL_INFO * AdditionalProtocols = 0;
unsigned long TotalAdditionalProtocols = 0;
#define RPC_REGISTRY_SECURITY_PROVIDERS \
"Software\\Microsoft\\Rpc\\SecurityService"
RPC_STATUS
RpcGetSecurityProviderInfo(
unsigned long AuthnId,
RPC_CHAR PAPI * PAPI * Dll,
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];
#ifdef NTENV
UNICODE_STRING AuthnIdWC;
#endif
wsprintf(AuthnIdZ, "%d", AuthnId);
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
RegStatus = RegQueryValueExA(
RegistryKey,
AuthnIdZ,
0,
&Type,
(unsigned char *)DllName,
&DllNameLength
);
RegCloseKey(RegistryKey);
if (RegStatus == ERROR_SUCCESS)
{
*Dll = DuplicateString(DllName);
if (*Dll == 0)
{
RegStatus = RPC_S_OUT_OF_MEMORY;
}
}
else
{
RegStatus = RPC_S_UNKNOWN_AUTHN_SERVICE;
}
return(RegStatus);
}
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, i;
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,
(LPTSTR) &Protseq,
&ProtseqLength,
0,
&Ignore,
(LPBYTE) MaxValueData,
&IgnoreLength
);
if (RegStatus == ERROR_SUCCESS)
{
//Add this to our table..
AdditionalProtocolsInfo->RpcProtocolSequence =
new unsigned char[ProtseqLength+1];
if (AdditionalProtocolsInfo->RpcProtocolSequence == 0)
{
Status = RPC_S_OUT_OF_MEMORY;
goto Cleanup;
}
RpcpMemoryCopy(
AdditionalProtocolsInfo->RpcProtocolSequence,
Protseq,
ProtseqLength+1
);
Value = (char * )&MaxValueData;
AdditionalProtocolsInfo->RpcSsEndpoint =
new unsigned char[Length = (lstrlen(Value) + 1)];
if (AdditionalProtocolsInfo->RpcSsEndpoint == 0)
{
Status = RPC_S_OUT_OF_MEMORY;
goto Cleanup;
}
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 unsigned int ServerSideFlag,
IN RPC_CHAR * 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.
--*/
{
RPC_PROTOCOL_SEQUENCE_MAP * RpcProtocolSequenceMap;
unsigned int Length, Index;
if ( ServerSideFlag != 0 )
{
RpcProtocolSequenceMap = ServerRpcProtocolSequenceMap;
Length = sizeof(ServerRpcProtocolSequenceMap)
/ sizeof(RPC_PROTOCOL_SEQUENCE_MAP);
}
else
{
RpcProtocolSequenceMap = ClientRpcProtocolSequenceMap;
Length = sizeof(ClientRpcProtocolSequenceMap)
/ sizeof(RPC_PROTOCOL_SEQUENCE_MAP);
}
for (Index = 0; Index < Length; Index++)
{
if ( RpcpStringCompare(RpcProtocolSequence,
RpcProtocolSequenceMap[Index].RpcProtocolSequence) == 0 )
{
return(RpcProtocolSequenceMap[Index].TransportInterfaceDll);
}
}
return(0);
}
RPC_STATUS
RpcConfigMapRpcProtocolSequence (
IN unsigned int ServerSideFlag,
IN RPC_CHAR * 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;
long RegStatus;
unsigned char * KeyString;
unsigned long Length;
TempString = LocalMapRpcProtocolSequence(ServerSideFlag,
RpcProtocolSequence);
if ( TempString != 0 )
{
*TransportInterfaceDll = new RPC_CHAR[RpcpStringLength(TempString) + 1];
if ( *TransportInterfaceDll == 0 )
{
return(RPC_S_OUT_OF_MEMORY);
}
RpcpMemoryCopy(*TransportInterfaceDll, TempString,
(RpcpStringLength(TempString) + 1) * sizeof(RPC_CHAR));
return(RPC_S_OK);
}
if ( ServerSideFlag == 0 )
{
KeyString = (unsigned char *) RPC_REGISTRY_CLIENT_PROTOCOLS;
}
else
{
KeyString = (unsigned char *) RPC_REGISTRY_SERVER_PROTOCOLS;
}
RegStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPSTR) KeyString,
0, 0, &RegistryKey);
if ( RegStatus != ERROR_SUCCESS )
{
return(RPC_S_PROTSEQ_NOT_SUPPORTED);
}
*TransportInterfaceDll = new RPC_CHAR[MAX_DLLNAME_LENGTH + 1];
if ( *TransportInterfaceDll == 0 )
{
return(RPC_S_OUT_OF_MEMORY);
}
Length = (MAX_DLLNAME_LENGTH + 1) * sizeof(RPC_CHAR);
RegStatus = RegQueryValueEx(RegistryKey, (LPSTR)RpcProtocolSequence, NULL, NULL,
(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 );
return(RPC_S_PROTSEQ_NOT_SUPPORTED);
}
RPC_STATUS
RpcConfigInquireProtocolSequences (
OUT RPC_PROTSEQ_VECTORW PAPI * PAPI * ProtseqVector
)
/*++
Routine Description:
This routine is used to obtain a list of the rpc protocol sequences
supported by the system for servers.
Arguments:
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 the specified rpc
protocol sequence.
--*/
{
#if 1
DWORD RegStatus, Index, Ignore, NumberOfValues, MaximumValueLength;
DWORD ClassLength = 64, ProtseqLength, IgnoreLength;
BYTE IgnoreData[MAX_DLLNAME_LENGTH];
FILETIME LastWriteTime;
HKEY RegistryKey;
unsigned char ClassName[64];
RegStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
(LPSTR) RPC_REGISTRY_SERVER_PROTOCOLS, 0, 0, &RegistryKey);
if ( RegStatus != ERROR_SUCCESS )
{
return(RPC_S_NO_PROTSEQS);
}
RegStatus = RegQueryInfoKey(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);
}
*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 < NumberOfValues; 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);
}
ProtseqLength = MAX_PROTSEQ_LENGTH;
IgnoreLength = MAX_DLLNAME_LENGTH;
RegStatus = RegEnumValue(RegistryKey, Index,
(LPSTR)(*ProtseqVector)->Protseq[Index], &ProtseqLength,
0, &Ignore, (LPBYTE) IgnoreData, &IgnoreLength);
ASSERT( RegStatus == ERROR_SUCCESS );
}
RegStatus = RegCloseKey(RegistryKey);
ASSERT( RegStatus == ERROR_SUCCESS );
return(RPC_S_OK);
#endif
#if 0
unsigned int Size;
unsigned int Index;
Size = sizeof(ServerRpcProtocolSequenceMap)
/ sizeof(RPC_PROTOCOL_SEQUENCE_MAP);
*ProtseqVector = (RPC_PROTSEQ_VECTOR *) new unsigned char[
sizeof(RPC_PROTSEQ_VECTOR) + (Size - 1)
* sizeof(RPC_CHAR *)];
if (*ProtseqVector == 0)
{
return(RPC_S_OUT_OF_MEMORY);
}
(*ProtseqVector)->Count = Size;
for (Index = 0; Index < Size; Index++)
(*ProtseqVector)->Protseq[Index] = 0;
for (Index = 0; Index < Size; Index++)
{
(*ProtseqVector)->Protseq[Index] = new RPC_CHAR[RpcpStringLength(
ServerRpcProtocolSequenceMap[Index].RpcProtocolSequence) + 1];
if ((*ProtseqVector)->Protseq[Index] == 0)
{
RpcProtseqVectorFree(ProtseqVector);
return(RPC_S_OUT_OF_MEMORY);
}
RpcpMemoryCopy((*ProtseqVector)->Protseq[Index],
ServerRpcProtocolSequenceMap[Index].RpcProtocolSequence,
(RpcpStringLength(
ServerRpcProtocolSequenceMap[Index].RpcProtocolSequence)
+ 1) * sizeof(RPC_CHAR));
}
return(RPC_S_OK);
#endif
}
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.
Return Value:
An unsigned long value will be returned.
--*/
{
return ((unsigned long)GetTickCount());
}
unsigned short
SomeShortValue (
)
/*++
See SomeLongValue.
--*/
{
return ((unsigned short)(GetTickCount() & 0xffff));
}
unsigned short
AnotherShortValue (
)
/*++
See SomeLongValue.
--*/
{
return ((unsigned short)(GetTickCount() & 0xffff));
}
unsigned char
SomeCharacterValue (
)
/*++
See SomeLongValue.
--*/
{
return ((unsigned char)(GetTickCount() & 0xff));
}
unsigned long WaitToGarbageCollectDelay;
unsigned int GcThreadStarted = 0;
unsigned int EnableGc = 0;
void
GarbageCollectionThread (
IN void PAPI * Ignore
)
/*++
Routine Description:
This is the routine executed by the garbage collection thread.
Arguments:
Ignore - just ignore this; it is not used.
--*/
{
UNUSED(Ignore);
for (;;)
{
PerformGarbageCollection();
PauseExecution(WaitToGarbageCollectDelay * 1000);
}
}
void
GarbageCollectionNeeded (
IN unsigned long EveryNumberOfSeconds
)
/*++
Routine Description:
If a protocol module needs to be called periodically to clean up
(garbage collect) idle resources, it will call this routine. We just
need to arrange things so that each protocol module gets called
periodically to do this.
--*/
{
RPC_STATUS RpcStatus = RPC_S_OK;
THREAD * Thread;
WaitToGarbageCollectDelay = EveryNumberOfSeconds;
if ( EnableGc != 0 )
{
if ( GcThreadStarted == 0 )
{
RequestGlobalMutex();
if ( GcThreadStarted == 0 )
{
Thread = new THREAD(GarbageCollectionThread, 0, &RpcStatus);
if (RpcStatus != RPC_S_OK) {
delete Thread;
} else if (Thread != 0) {
GcThreadStarted = 1;
}
}
ClearGlobalMutex();
}
}
}
RPC_STATUS
EnableGarbageCollection (
void
)
/*++
Routine Description:
We need to enable garbage collection.
Return Value:
RPC_S_OK - This value will always be returned.
--*/
{
EnableGc = 1;
return(RPC_S_OK);
}
long RPC_ENTRY
I_RpcMapWin32Status(
IN RPC_STATUS Status
)
{
return ((unsigned long)Status);
}
unsigned char *
UnicodeToAnsiString(
IN RPC_CHAR * UnicodeString,
OUT RPC_STATUS * RpcStatus
)
{
unsigned char * NewString;
NewString = DuplicateString(UnicodeString); // Not really unicode.
if (NewString == NULL) {
*RpcStatus = RPC_S_OUT_OF_MEMORY;
return (NULL);
}
*RpcStatus = RPC_S_OK;
return (NewString);
}