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.
 
 
 
 
 
 

695 lines
14 KiB

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
Misc.cxx
Abstract:
Initalization, Heap, debug, thread manager for OR
Author:
Mario Goertzel [MarioGo]
Revision History:
MarioGo 02-11-95 Bits 'n pieces
--*/
#include <or.hxx>
BOOL fListened = FALSE;
ORSTATUS
StartListeningIfNecessary()
/*++
Routine Description:
If the process has not successfully listened to remote
protocols this routine will try do to so.
BUGBUG: Should really have a named event signaled by
the system when the network is started.
BUGBUG: Should interact with plug-n-play and DHCP better.
Note:
Will not add ncacn_np to the list of supported Network OLE
protocols because RpcBindingServerFromClient() doesn't
work on named pipes and is required to unmarshal an in
interface pointer.
Arguments:
n/a
Return Value:
OR_OK - Success.
OR_NOMEM - Resource problems.
--*/
{
RPC_STATUS status;
PWSTR pwstr = gpwstrProtseqs;
USHORT id;
if (fListened == TRUE)
{
return(OR_OK);
}
gpClientLock->LockExclusive();
if (fListened == TRUE)
{
gpClientLock->UnlockExclusive();
return(OR_OK);
}
if (pwstr)
{
while(*pwstr)
{
id = GetProtseqId(pwstr);
if (0 != id)
{
status = UseProtseqIfNecessary(id);
if (status == RPC_S_OK)
{
fListened = TRUE;
}
}
pwstr = OrStringSearch(pwstr, 0) + 1;
}
}
if ( FALSE == fListened
&& 0 != gLocalMid)
{
// Didn't manage to listen to anything new, no need to
// recompute all the global arrays.
gpClientLock->UnlockExclusive();
return(OR_OK);
}
// ??? limit to only those protseqs listed in the registry,
// if the another service used more protseqs they would show up here.
RPC_BINDING_VECTOR *pbv;
PWSTR pwstrT;
DUALSTRINGARRAY *pdsaT;
PWSTR *aAddresses;
USHORT *aProtseqs;
DWORD psaLen;
DWORD i;
status = RpcServerInqBindings(&pbv);
if (RPC_S_OK == status)
{
aAddresses = new PWSTR[pbv->Count];
aProtseqs = new USHORT[pbv->Count];
if ( !aAddresses
|| !aProtseqs)
{
RpcBindingVectorFree(&pbv);
delete aAddresses; // 0 or allocated.
delete aProtseqs; // 0 or allocated.
status = OR_NOMEM;
}
}
else
status = OR_NOMEM;
if (status != OR_OK)
{
gpClientLock->UnlockExclusive();
return(status);
}
// Build array of protseqs id's and addresses we're listening to.
for(psaLen = 0, i = 0; i < pbv->Count; i++)
{
PWSTR pwstrStringBinding;
status = RpcBindingToStringBinding(pbv->BindingH[i], &pwstrStringBinding);
if (status != RPC_S_OK)
{
break;
}
ASSERT(pwstrStringBinding);
status = RpcStringBindingParse(pwstrStringBinding,
0,
&pwstrT,
&aAddresses[i],
0,
0);
RPC_STATUS statusT = RpcStringFree(&pwstrStringBinding);
ASSERT(statusT == RPC_S_OK && pwstrStringBinding == 0);
if (status != RPC_S_OK)
{
break;
}
aProtseqs[i] = GetProtseqId(pwstrT);
status = RpcStringFree(&pwstrT);
ASSERT(status == RPC_S_OK && pwstrT == 0);
if (!IsLocal(aProtseqs[i]) && aProtseqs[i] != ID_NP)
{
// Only hand out remote non-named pipes protseqs.
psaLen += 1 + OrStringLen(aAddresses[i]) + 1;
}
}
if (status != RPC_S_OK)
{
delete aAddresses;
delete aProtseqs;
status = RpcBindingVectorFree(&pbv);
ASSERT(pbv == 0 && status == RPC_S_OK);
gpClientLock->UnlockExclusive();
return(status);
}
// string bindings final null, authn and authz service and two final nulls
if (psaLen == 0)
{
// No remote bindings
psaLen = 1;
}
psaLen += 1 + 2 + 2;
pdsaT = new(psaLen * sizeof(WCHAR)) DUALSTRINGARRAY;
pdsaT->wNumEntries = psaLen;
pdsaT->wSecurityOffset = psaLen - 4;
pwstrT = pdsaT->aStringArray;
for (i = 0; i < pbv->Count; i++)
{
if (!IsLocal(aProtseqs[i]) && aProtseqs[i] != ID_NP)
{
*pwstrT = aProtseqs[i];
pwstrT++;
OrStringCopy(pwstrT, aAddresses[i]);
pwstrT = OrStringSearch(pwstrT, 0) + 1; // next
}
status = RpcStringFree(&aAddresses[i]);
ASSERT(status == RPC_S_OK);
}
if (psaLen == 6)
{
// No remote bindings, put in first null.
pdsaT->aStringArray[0] = 0;
pwstrT++;
}
// Zero final terminator
*pwstrT = 0;
// Security authn service
pwstrT++;
*pwstrT = RPC_C_AUTHN_WINNT;
// Authz service, -1 means none
pwstrT++;
*pwstrT = -1;
// Final, final NULLS
pwstrT++;
pwstrT[0] = 0;
pwstrT[1] = 0;
ASSERT(dsaValid(pdsaT));
USHORT cRemoteProtseqs = 0;
// Convert aProtseqs into remote only array of protseqs and count them.
for(i = 0; i < pbv->Count; i++)
{
if (IsLocal(aProtseqs[i]) == FALSE && aProtseqs[i] != ID_NP)
{
aProtseqs[cRemoteProtseqs] = aProtseqs[i];
cRemoteProtseqs++;
}
}
delete aAddresses;
status = RpcBindingVectorFree(&pbv);
ASSERT(pbv == 0 && status == RPC_S_OK);
CMid *pMid = new(pdsaT->wNumEntries * sizeof(WCHAR)) CMid(pdsaT, TRUE, gLocalMid);
if (pMid)
{
gpMidTable->Add(pMid);
}
else
{
delete pdsaT;
delete aProtseqs;
gpClientLock->UnlockExclusive();
return(OR_NOMEM);
}
// Update globals
aMyProtseqs = aProtseqs;
cMyProtseqs = cRemoteProtseqs;
pdsaMyBindings = pdsaT;
gLocalMid = pMid->Id();
gpClientLock->UnlockExclusive();
return(OR_OK);
}
DWORD
RegisterAuthInfoIfNecessary()
{
DWORD Status;
//
// No locks, doesn't matter if we call RegisterAuthInfo more than
// once by chance.
//
if ( gfRegisteredAuthInfo )
return ERROR_SUCCESS;
Status = RpcServerRegisterAuthInfo(NULL,
RPC_C_AUTHN_WINNT,
NULL,
NULL);
if ( Status == RPC_S_OK )
gfRegisteredAuthInfo = TRUE;
if ( Status == RPC_S_UNKNOWN_AUTHN_SERVICE )
{
Status = RPC_S_OK;
}
return Status;
}
//
// Local ID allocation
//
ID
AllocateId(
IN LONG cRange
)
/*++
Routine Description:
Allocates a unique local ID.
This id is 64bits. The low 32 bits are a sequence number which
is incremented with each call. The high 32bits are seconds
since 1980. The ID of 0 is not used.
Limitations:
No more then 2^32 IDs can be generated in a given second without a duplicate.
When the time stamp overflows, once every >126 years, the sequence numbers
are likely to be generated in such a way as to collide with those from 126
years ago.
There is no prevision in the code to deal with overflow or duplications.
Arguments:
cRange - Number to allocate in sequence, default is 1.
Return Value:
A 64bit id.
--*/
{
static LONG sequence = 1;
FILETIME ft;
LARGE_INTEGER id;
DWORD seconds;
BOOL fSuccess;
ASSERT(cRange > 0 && cRange < 11);
GetSystemTimeAsFileTime(&ft);
fSuccess = RtlTimeToSecondsSince1980((PLARGE_INTEGER)&ft,
&seconds);
ASSERT(fSuccess); // Only fails when time is <1980 or >2115
do
{
id.HighPart = seconds;
id.LowPart = InterlockedExchangeAdd(&sequence, cRange);
}
while (id.QuadPart == 0 );
return(id.QuadPart);
}
//
// Global Heaps
//
HANDLE hProcessHeap;
HANDLE hObjHeap;
HANDLE hSetHeap;
//
// The OR uses three heaps:
//
// The process heap is used for MIDL_user_allocate and free. Objects in
// this heap are short lived. It maybe accessed by several threads at
// once.
//
// The object heap is used for PROCESS, OXID and OID structures.
// This heap is serialized and is used for long lived objects.
//
// The set heap is used for SET objects (both local and remote).
// Access is serialized with the SET table lock. Objects are long
// lived and accessed regularly (every ping period).
//
#if DBG
typedef struct DbgBlock {
struct DbgBlock *Next;
struct DbgBlock *Previous;
DWORD Tag;
DWORD Size;
// Data // User sized, no pad.
UCHAR Guard[4]; // after the data in real block.
} DBG_BLOCK;
DBG_BLOCK *OrDbgHeapList = 0;
CRITICAL_SECTION DbgHeapLock;
#endif
//
ORSTATUS InitHeaps()
{
ORSTATUS Status = OR_OK;
#if DBG
static int heapinit = 0;
ASSERT(!heapinit);
heapinit++;
#endif
hProcessHeap = GetProcessHeap();
ASSERT(hProcessHeap);
hSetHeap = 0; // HeapCreate(HEAP_NO_SERIALIZE, 2*4096 - 100, 0);
hObjHeap = HeapCreate(0, 2*4096 - 100, 0);
if (!hObjHeap)
{
// Not catastrophic
hObjHeap = hProcessHeap;
}
if (!hSetHeap)
{
// Not catastrophic
hSetHeap = hProcessHeap;
}
#if DBG
InitializeCriticalSection(&DbgHeapLock);
#endif
return(Status);
}
#if DBG
void DbgCheckHeap(BOOL quick = TRUE)
{
DBG_BLOCK *pblock;
UINT size;
INT count = -1;
if (quick)
{
count = 3;
}
CMutexLock lock(&DbgHeapLock);
pblock = OrDbgHeapList;
while(pblock && count != 0)
{
size = pblock->Size;
ASSERT(pblock->Guard[size+0] == 0xce);
ASSERT(pblock->Guard[size+1] == 0xfa);
ASSERT(pblock->Guard[size+2] == 0xbe);
ASSERT(pblock->Guard[size+3] == 0xba);
ASSERT((pblock->Tag & 0xFFFF0000) == 0xA1A10000);
if (pblock->Next)
{
ASSERT(pblock->Next->Previous == pblock);
}
pblock = pblock->Next;
count--;
}
}
#endif
inline LPVOID OrAlloc(UINT size, USHORT tag)
{
LPVOID p;
HANDLE h;
#if DBG
DBG_BLOCK *pblock;
DbgCheckHeap();
ASSERT( ((LONG)size) >= 0 );
ASSERT( ((ULONG)size) < (ULONG)(1<<30) );
size+= sizeof(struct DbgBlock);
#endif
switch(tag)
{
case PROC_TAG:
h = hProcessHeap;
break;
case OBJ_TAG:
h = hObjHeap;
break;
case SET_TAG:
h = hSetHeap;
break;
default:
ASSERT(0);
}
p = HeapAlloc(h, 0, size);
#if DBG
size -= sizeof(struct DbgBlock);
if (p)
{
pblock = (DBG_BLOCK *)p;
pblock->Size = size;
pblock->Tag = 0xA1A10000 | tag;
pblock->Guard[size+0] = 0xce;
pblock->Guard[size+1] = 0xfa;
pblock->Guard[size+2] = 0xbe;
pblock->Guard[size+3] = 0xba;
pblock->Previous = 0;
CMutexLock lock(&DbgHeapLock);
pblock->Next = OrDbgHeapList;
if (pblock->Next)
{
pblock->Next->Previous = pblock;
}
OrDbgHeapList = pblock;
p = &pblock->Guard[0];
}
else
{
p = NULL;
}
#endif
return(p);
}
inline void OrFree(PVOID p, USHORT tag)
{
HANDLE h;
#if DBG
DBG_BLOCK *pblock;
ASSERT(p);
p = pblock = (DBG_BLOCK *)(((UCHAR *)p) - sizeof(DBG_BLOCK) + 4);
ASSERT(pblock->Tag == (0xA1A10000 | tag));
DbgCheckHeap();
CMutexLock lock(&DbgHeapLock);
pblock->Tag = 0xFEFE0000 | ~tag;
if (pblock == OrDbgHeapList)
{
OrDbgHeapList = OrDbgHeapList->Next;
}
if (pblock->Next)
{
pblock->Next->Previous = pblock->Previous;
}
if (pblock->Previous)
{
pblock->Previous->Next = pblock->Next;
}
lock.Unlock();
#endif
switch(tag)
{
case PROC_TAG:
h = hProcessHeap;
break;
case OBJ_TAG:
h = hObjHeap;
break;
case SET_TAG:
h = hSetHeap;
break;
default:
ASSERT(0);
}
HeapFree(h, 0, p);
return;
}
void * _CRTAPI1
operator new (
IN size_t size
)
{
return(OrAlloc(size, OBJ_TAG));
}
void * _CRTAPI1
operator new (
IN size_t size,
IN size_t extra
)
{
return(OrAlloc(size + extra, OBJ_TAG));
}
void _CRTAPI1
operator delete (
IN void * obj
)
{
if (obj == 0) return;
OrFree(obj, OBJ_TAG);
}
//
// Debug helper(s)
//
#if DBG
int __cdecl __RPC_FAR ValidateError(
IN ORSTATUS Status,
IN ...)
/*++
Routine Description
Tests that 'Status' is one of an expected set of error codes.
Used on debug builds as part of the VALIDATE() macro.
Example:
VALIDATE( (Status,
OR_BADSET,
// more error codes here
OR_OK,
0) // list must be terminated with 0
);
This function is called with the OrStatus and expected errors codes
as parameters. If OrStatus is not one of the expected error
codes and it not zero a message will be printed to the debugger
and the function will return false. The VALIDATE macro ASSERT's the
return value.
Arguments:
Status - Status code in question.
... - One or more expected status codes. Terminated with 0 (OR_OK).
Return Value:
TRUE - Status code is in the list or the status is 0.
FALSE - Status code is not in the list.
--*/
{
RPC_STATUS CurrentStatus;
va_list Marker;
if (Status == 0) return(TRUE);
va_start(Marker, Status);
while(CurrentStatus = va_arg(Marker, RPC_STATUS))
{
if (CurrentStatus == Status)
{
return(TRUE);
}
}
va_end(Marker);
OrDbgPrint(("OR Assertion: unexpected failure %lu (0x%p)\n",
(unsigned long)Status, (unsigned long)Status));
return(FALSE);
}
#endif