mirror of https://github.com/tongzx/nt5src
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.
3256 lines
73 KiB
3256 lines
73 KiB
/*++
|
|
|
|
Copyright (C) Microsoft Corporation, 1991 - 1999
|
|
|
|
Module Name:
|
|
|
|
worker.c
|
|
|
|
Abstract:
|
|
|
|
This file contains the real stuff for the EP Mapper.
|
|
|
|
Author:
|
|
|
|
Bharat Shah (barat) 17-2-92
|
|
|
|
Revision History:
|
|
|
|
06-03-97 gopalp Added code to cleanup stale EP Mapper entries.
|
|
|
|
--*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <sysinc.h>
|
|
#include <wincrypt.h>
|
|
#include <rpc.h>
|
|
#include <rpcndr.h>
|
|
#include "epmp.h"
|
|
#include "eptypes.h"
|
|
#include "local.h"
|
|
#include "twrproto.h"
|
|
#include <winsock2.h>
|
|
|
|
#define StringCompareA lstrcmpiA
|
|
#define StringLengthA lstrlenA
|
|
|
|
#define EP_S_DUPLICATE_ENTRY 0x16c9a0d8
|
|
RPC_IF_ID LocalNullUuid = {0};
|
|
|
|
UUID MgmtIf = {
|
|
0xafa8bd80,
|
|
0x7d8a,
|
|
0x11c9,
|
|
{0xbe, 0xf4, 0x08, 0x00, 0x2b, 0x10, 0x29, 0x89}
|
|
};
|
|
|
|
const int IP_ADDR_OFFSET = 0x4b;
|
|
|
|
void
|
|
PatchTower(
|
|
IN OUT twr_t *Tower,
|
|
IN int address)
|
|
{
|
|
int UNALIGNED *pIPAddr;
|
|
|
|
pIPAddr = (int UNALIGNED *) (((char *) Tower) + IP_ADDR_OFFSET);
|
|
|
|
//
|
|
// Patch the tower
|
|
//
|
|
*pIPAddr = address;
|
|
}
|
|
|
|
//
|
|
// Forward definitions
|
|
//
|
|
|
|
USHORT
|
|
GetProtseqIdAnsi(
|
|
PSTR Protseq
|
|
);
|
|
|
|
RPC_STATUS
|
|
DelayedUseProtseq(
|
|
USHORT id
|
|
);
|
|
|
|
VOID
|
|
CompleteDelayedUseProtseqs(
|
|
void
|
|
);
|
|
|
|
void
|
|
DeletePSEP(
|
|
PIFOBJNode Node,
|
|
char * Protseq,
|
|
char * Endpoint
|
|
);
|
|
|
|
void
|
|
PurgeOldEntries(
|
|
PIFOBJNode Node,
|
|
PPSEPNode List,
|
|
BOOL StrictMatch
|
|
);
|
|
|
|
RPC_STATUS
|
|
MatchPSAndEP (
|
|
PPSEPNode Node,
|
|
void *Pseq,
|
|
void * Endpoint,
|
|
unsigned long Version
|
|
);
|
|
|
|
PPSEPNode
|
|
FindPSEP (
|
|
register PPSEPNode List,
|
|
char * Pseq,
|
|
char * Endpoint,
|
|
unsigned long Version,
|
|
PFNPointer2 Compare
|
|
);
|
|
|
|
PIFOBJNode
|
|
FindIFOBJNode(
|
|
register PIFOBJNode List,
|
|
UUID * Obj,
|
|
UUID * IF,
|
|
unsigned long Version,
|
|
unsigned long Inq,
|
|
unsigned long VersOpts,
|
|
PFNPointer Compare
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
PIENTRY
|
|
MatchByKey(
|
|
register PIENTRY pList,
|
|
unsigned long key
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine Seqrches the Link-list of IF-OBJ nodes based on
|
|
key supplied.
|
|
|
|
Arguments:
|
|
|
|
List - The Linked list [head] - to be searched
|
|
|
|
key - The Id
|
|
|
|
Return Value:
|
|
|
|
Returns a pointer to the matching IFObj node in the list or returns NULL.
|
|
|
|
--*/
|
|
{
|
|
CheckInSem();
|
|
|
|
for (; pList && pList->Id < key; pList = pList->Next)
|
|
{
|
|
; // Empty body
|
|
}
|
|
|
|
return(pList);
|
|
}
|
|
|
|
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
GetForwardEp(
|
|
UUID *IfId,
|
|
RPC_VERSION * IFVersion,
|
|
UUID *Object,
|
|
unsigned char * Protseq,
|
|
void * * EpString
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Server rutime has received a pkt destined for a dynamically
|
|
declared endpoint. Epmapper must return the servers endpoint
|
|
to enable the runtime to correctly forward the pkt.
|
|
|
|
Arguments:
|
|
|
|
IF - Server Interface UUID
|
|
|
|
IFVersion - Version of the Interface
|
|
|
|
Obj - UUID of the Object
|
|
|
|
Protseq - Ptotocol sequence the interface is using.
|
|
|
|
EpString - Place to store the endpoint structure.
|
|
|
|
Return Value:
|
|
|
|
Returns a pointer to a string containing the server's endpoint.
|
|
|
|
RPC_S_OUT_OF_MEMORY
|
|
EPT_S_NOT_REGISTERED
|
|
|
|
---*/
|
|
{
|
|
|
|
PIFOBJNode pNode;
|
|
PPSEPNode pPSEPNode;
|
|
unsigned short len;
|
|
char * String;
|
|
PFNPointer Match;
|
|
unsigned long InqType;
|
|
unsigned long Version = VERSION(IFVersion->MajorVersion,
|
|
IFVersion->MinorVersion);
|
|
|
|
if (memcmp((char *)IfId, (char *)&MgmtIf, sizeof(UUID)) == 0)
|
|
{
|
|
InqType = RPC_C_EP_MATCH_BY_OBJ;
|
|
Match = SearchIFObjNode;
|
|
}
|
|
else
|
|
{
|
|
InqType = 0;
|
|
Match = WildCardMatch;
|
|
}
|
|
|
|
*EpString = 0;
|
|
|
|
EnterSem();
|
|
|
|
pNode = IFObjList;
|
|
|
|
if (pNode == 0)
|
|
{
|
|
LeaveSem();
|
|
return(EPT_S_NOT_REGISTERED);
|
|
}
|
|
|
|
while (pNode != 0)
|
|
{
|
|
pNode = FindIFOBJNode(
|
|
pNode,
|
|
Object,
|
|
IfId,
|
|
Version,
|
|
InqType,
|
|
0,
|
|
Match
|
|
);
|
|
|
|
if (pNode == 0)
|
|
{
|
|
LeaveSem();
|
|
return(EPT_S_NOT_REGISTERED);
|
|
}
|
|
|
|
pPSEPNode = pNode->PSEPlist;
|
|
|
|
pPSEPNode = FindPSEP(
|
|
pPSEPNode,
|
|
Protseq,
|
|
NULL,
|
|
0L,
|
|
MatchPSAndEP
|
|
);
|
|
|
|
if (pPSEPNode == 0)
|
|
{
|
|
pNode = pNode->Next;
|
|
if (pNode == 0)
|
|
{
|
|
LeaveSem();
|
|
return(EPT_S_NOT_REGISTERED);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
|
|
// We now have a PSEPNode. We just ought to return the first one!
|
|
|
|
// Use I_RpcAllocate To Allocate because runtime will free this!
|
|
String = I_RpcAllocate( len = (strlen(pPSEPNode->EP) + 1) );
|
|
if (String == 0)
|
|
{
|
|
LeaveSem();
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
// Do we really need memset()?. memcpy set the bytes...
|
|
memset(String, 0, len);
|
|
memcpy(String, pPSEPNode->EP, len);
|
|
|
|
*EpString = String;
|
|
LeaveSem();
|
|
|
|
return(RPC_S_OK);
|
|
} // while loop
|
|
|
|
// we never go through here.
|
|
return(EPT_S_NOT_REGISTERED);
|
|
}
|
|
|
|
|
|
|
|
|
|
RPC_STATUS
|
|
SearchIFObjNode(
|
|
PIFOBJNode pNode,
|
|
UUID *Object,
|
|
UUID *IfUuid,
|
|
unsigned long Version,
|
|
unsigned long InqType,
|
|
unsigned long VersOption
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine Seqrches the Link-list of IF-OBJ nodes based on
|
|
Obj, IFUuid, IFVersion, Inqtype [Ignore OBJ, IgnoreIF, etc],
|
|
and VersOption [Identical Ver, Compatible Vers. etc]
|
|
|
|
Arguments:
|
|
|
|
List - The Linked list head - to be searched
|
|
|
|
Obj - UUID of the Object
|
|
|
|
IF - Interface UUID
|
|
|
|
Version - Version of the Interface
|
|
|
|
InqType - Type of Inquiry [Filter options based on IF/Obj/Both
|
|
|
|
VersOpts - Filter options based on Version
|
|
|
|
Return Value:
|
|
|
|
Returns a pointer to the matching IFObj node in the list or returns NULL.
|
|
|
|
--*/
|
|
{
|
|
switch (InqType)
|
|
{
|
|
default:
|
|
case RPC_C_EP_ALL_ELTS:
|
|
return 0;
|
|
|
|
case RPC_C_EP_MATCH_BY_BOTH:
|
|
if (memcmp(
|
|
(char *)&pNode->ObjUuid,
|
|
(char *)Object,
|
|
sizeof(UUID))
|
|
)
|
|
return(1);
|
|
// Intentionally Fall through ..
|
|
|
|
case RPC_C_EP_MATCH_BY_IF:
|
|
return(!(
|
|
(
|
|
!memcmp(
|
|
(char *)&pNode->IFUuid,
|
|
(char *)IfUuid,
|
|
sizeof(UUID)
|
|
)
|
|
)
|
|
&&
|
|
(
|
|
( (VersOption == RPC_C_VERS_UPTO)
|
|
&& pNode->IFVersion <= Version)
|
|
|| ( (VersOption == RPC_C_VERS_COMPATIBLE)
|
|
&& ((pNode->IFVersion & 0xFFFF0000) ==
|
|
(Version & 0xFFFF0000))
|
|
&& (pNode->IFVersion >= Version)
|
|
)
|
|
|| ( (VersOption == RPC_C_VERS_EXACT)
|
|
&& (pNode->IFVersion == Version)
|
|
)
|
|
|| (VersOption == RPC_C_VERS_ALL)
|
|
|| ( (VersOption == RPC_C_VERS_MAJOR_ONLY)
|
|
&& ((pNode->IFVersion & 0xFFFF0000L)
|
|
== (Version & 0xFFFF0000L))
|
|
)
|
|
|| ( (VersOption ==
|
|
I_RPC_C_VERS_UPTO_AND_COMPATIBLE)
|
|
&& ((pNode->IFVersion & 0xFFFF0000L)
|
|
== (Version & 0xFFFF0000L))
|
|
&& (pNode->IFVersion <= Version)
|
|
)
|
|
)
|
|
)
|
|
); // return(
|
|
|
|
case RPC_C_EP_MATCH_BY_OBJ:
|
|
return(
|
|
memcmp(
|
|
(char *)&pNode->ObjUuid,
|
|
(char *)Object,
|
|
sizeof(UUID)
|
|
)
|
|
);
|
|
} // switch
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PIFOBJNode
|
|
FindIFOBJNode(
|
|
register PIFOBJNode List,
|
|
UUID * Obj,
|
|
UUID * IF,
|
|
unsigned long Version,
|
|
unsigned long Inq,
|
|
unsigned long VersOpts,
|
|
PFNPointer Compare
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine Seqrches the Link-list of IF-OBJ nodes based on
|
|
Obj and IF specified.
|
|
|
|
Arguments:
|
|
|
|
List - The Linked list head - to be searched
|
|
|
|
Obj - UUID of the Object
|
|
|
|
IF - Interface UUID
|
|
|
|
Version - Version of the Interface
|
|
|
|
Inq - Type of Inquiry [Filter based on IF/OB/Both]
|
|
|
|
VersOpt - Filter based on version [<=, >=, == etc]
|
|
|
|
Compare() - A pointer to function used for searching.
|
|
WildCardMatch or ExactMatch.
|
|
|
|
Return Value:
|
|
|
|
Returns a pointer to the matching IFObj node in the list or returns NULL.
|
|
|
|
--*/
|
|
{
|
|
CheckInSem();
|
|
|
|
for (; (List !=NULL) && (*Compare)(List, Obj, IF, Version, Inq, VersOpts);
|
|
List = List->Next)
|
|
{
|
|
; // Empty body
|
|
}
|
|
|
|
return (List);
|
|
}
|
|
|
|
|
|
|
|
|
|
PPSEPNode
|
|
FindPSEP (
|
|
register PPSEPNode List,
|
|
char * Pseq,
|
|
char * Endpoint,
|
|
unsigned long Version,
|
|
PFNPointer2 Compare
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine Seqrches the Link-list of PSEP nodes based on
|
|
Protocol sequence and Endpoint specified.
|
|
|
|
Arguments:
|
|
|
|
List - The Linked list head - to be searched
|
|
|
|
Pseq - Protocol sequence string specified
|
|
|
|
Endpoint - Endpoint string specified
|
|
|
|
Version - Version of the Interface
|
|
|
|
Compare() - A pointer to function used for searching.
|
|
|
|
Return Value:
|
|
|
|
Returns a pointer to the matching PSEP node in the list or returns NULL.
|
|
|
|
--*/
|
|
{
|
|
CheckInSem();
|
|
|
|
for (; List && (*Compare)(List, Pseq, Endpoint, Version); List = List->Next)
|
|
{
|
|
; // Empty body
|
|
}
|
|
|
|
return (List);
|
|
|
|
if (Version); // May need this if we overload FindNode and collapse
|
|
// FindPSEP and FindIFOBJ
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
ExactMatch(
|
|
PIFOBJNode Node,
|
|
UUID *Obj,
|
|
UUID *IF,
|
|
unsigned long Version,
|
|
unsigned long InqType,
|
|
unsigned long VersOptions
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine compares a Node in the IFOBJList to [Obj, IF, Version] triple
|
|
and returns 0 if there is an exact match else returns 1
|
|
|
|
Arguments:
|
|
|
|
Node - An IFOBJ node
|
|
|
|
Obj - UUID of the Object
|
|
|
|
IF - Interface UUID
|
|
|
|
Version - Version of the Interface
|
|
|
|
Return Value:
|
|
|
|
Returns 0 if there is an exact match; 1 otherwise
|
|
|
|
--*/
|
|
{
|
|
return(( memcmp(&Node->ObjUuid, Obj,sizeof(UUID))
|
|
|| memcmp(&Node->IFUuid, IF, sizeof(UUID))
|
|
|| (Node->IFVersion != Version)));
|
|
}
|
|
|
|
|
|
|
|
|
|
RPC_STATUS
|
|
WildCardMatch (
|
|
PIFOBJNode Node,
|
|
UUID *Obj,
|
|
UUID *IF,
|
|
unsigned long Version,
|
|
unsigned long InqType,
|
|
unsigned long VersOptions
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine compares a Node in the IFOBJList to [Obj, IF, Version] triple
|
|
and returns 0 if there is an exact match or if registered IF-Obj node
|
|
has a NULL Obj UUid and version of the registed IF_Obj is >= that
|
|
supplied
|
|
|
|
Arguments:
|
|
|
|
Node - An IFOBJ node
|
|
|
|
Obj - UUID of the Object
|
|
|
|
IF - Interface UUID
|
|
|
|
Version - Version of the Interface
|
|
|
|
Return Value:
|
|
|
|
Returns 0 if there is a wild card match ; 1 otherwise
|
|
|
|
--*/
|
|
{
|
|
if ( (!memcmp(&Node->IFUuid, IF, sizeof(UUID)))
|
|
&& ((Node->IFVersion & 0xFFFF0000L) == (Version & 0xFFFF0000L))
|
|
&& (Node->IFVersion >= Version)
|
|
&& ((!memcmp(&Node->ObjUuid, Obj, sizeof(UUID))) ||
|
|
(IsNullUuid(&Node->ObjUuid)) ) )
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
return(1);
|
|
}
|
|
|
|
|
|
|
|
RPC_STATUS
|
|
MatchPSAndEP (
|
|
PPSEPNode Node,
|
|
void *Pseq,
|
|
void * Endpoint,
|
|
unsigned long Version
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine Matches A Node on PSEP list with given Protseq and Endpoint
|
|
If Pseq is given pseqs are matched, if Endpoint is given Endpoints
|
|
are matched, if neither is given returns true, if both are given
|
|
both are matched.
|
|
|
|
Arguments:
|
|
|
|
Node - A PSEP node on PSEP list.
|
|
|
|
Pseq - Protocol Sequence string
|
|
|
|
Endpoint - Endpoint string
|
|
|
|
Return Value:
|
|
|
|
Returns 0 if Matched successfully, 1 otherwise.
|
|
|
|
--*/
|
|
{
|
|
return ( (Pseq && RpcpStringCompareA(Node->Protseq, Pseq))
|
|
|| (Endpoint && RpcpStringCompareA(Node->EP, Endpoint)) );
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
PurgeOldEntries(
|
|
PIFOBJNode Node,
|
|
PPSEPNode List,
|
|
BOOL StrictMatch
|
|
)
|
|
{
|
|
PPSEPNode Tmp, DeleteMe;
|
|
char * Endpoint = 0;
|
|
|
|
CheckInSem();
|
|
|
|
Tmp = Node->PSEPlist;
|
|
|
|
while (Tmp != 0)
|
|
{
|
|
if (StrictMatch == TRUE)
|
|
Endpoint = Tmp->EP;
|
|
|
|
if (DeleteMe = FindPSEP(List, Tmp->Protseq, Endpoint, 0L, MatchPSAndEP))
|
|
{
|
|
DeleteMe = Tmp;
|
|
Tmp = Tmp->Next;
|
|
UnLinkFromPSEPList(&Node->PSEPlist, DeleteMe);
|
|
DeleteMe->Signature = FREE;
|
|
FreeMem(DeleteMe);
|
|
}
|
|
else
|
|
{
|
|
Tmp = Tmp->Next;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
RPC_STATUS
|
|
IsNullUuid (
|
|
UUID * Uuid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine checks if a UUID is Nil
|
|
|
|
Arguments:
|
|
|
|
Uuid - UUID to be tested
|
|
|
|
Return Value:
|
|
|
|
Returns 1 if it is a Nil UUID
|
|
0 otherwise.
|
|
|
|
--*/
|
|
{
|
|
unsigned long PAPI * Vector;
|
|
|
|
Vector = (unsigned long PAPI *) Uuid;
|
|
|
|
if ( (Vector[0] == 0)
|
|
&& (Vector[1] == 0)
|
|
&& (Vector[2] == 0)
|
|
&& (Vector[3] == 0))
|
|
return(1);
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
|
|
twr_p_t
|
|
NewTower(
|
|
twr_p_t Tower
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns a New, Duplicated tower
|
|
|
|
Arguments:
|
|
|
|
Tower - The tower that needs to be duplicated.
|
|
|
|
Return Value:
|
|
|
|
Retunes a pointer to a new tower if successful else returns
|
|
NULL
|
|
|
|
--*/
|
|
{
|
|
unsigned short len;
|
|
twr_p_t NewTower;
|
|
|
|
len = (unsigned short)(sizeof(Tower->tower_length) + Tower->tower_length);
|
|
|
|
if ((NewTower = MIDL_user_allocate(len)) != NULL)
|
|
{
|
|
memcpy((char *)NewTower, (char *)Tower, len);
|
|
}
|
|
|
|
return(NewTower);
|
|
}
|
|
|
|
|
|
const unsigned long EPLookupHandleSignature = 0xFAFAFAFA;
|
|
|
|
|
|
PSAVEDCONTEXT
|
|
GetNewContext(
|
|
unsigned long Type
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
++*/
|
|
{
|
|
PSAVEDCONTEXT Context;
|
|
|
|
if ( ((Context = AllocMem(sizeof(SAVEDCONTEXT))) == 0) )
|
|
return 0;
|
|
|
|
memset(Context, 0, sizeof(SAVEDCONTEXT));
|
|
|
|
Context->Cb = sizeof(SAVEDCONTEXT);
|
|
Context->Type = Type;
|
|
Context->Signature = EPLookupHandleSignature;
|
|
EnLinkContext(Context);
|
|
|
|
return(Context);
|
|
}
|
|
|
|
const unsigned int EPMapSignature = 0xCBBCCBBC;
|
|
const unsigned int EPLookupSignature = 0xABBAABBA;
|
|
|
|
|
|
RPC_STATUS
|
|
AddToSavedContext(
|
|
PSAVEDCONTEXT Context,
|
|
PIFOBJNode Node,
|
|
PPSEPNode Psep,
|
|
unsigned long Calltype,
|
|
BOOL fPatchTower,
|
|
int PatchTowerAddress
|
|
)
|
|
{
|
|
void * NewNode;
|
|
PSAVEDTOWER SavedTower;
|
|
PSAVED_EPT SavedEndpoint;
|
|
unsigned long Size;
|
|
unsigned long TowerSize;
|
|
|
|
ASSERT(Calltype == Context->Type);
|
|
|
|
switch (Calltype)
|
|
{
|
|
case EP_MAP:
|
|
Size = sizeof(SAVEDTOWER) ;
|
|
if ((NewNode = AllocMem(Size)) == 0)
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
|
|
SavedTower = (PSAVEDTOWER) NewNode;
|
|
memset(SavedTower, 0, Size);
|
|
SavedTower->Cb = Size;
|
|
SavedTower->Signature = EPMapSignature;
|
|
SavedTower->Tower = NewTower(Psep->Tower);
|
|
|
|
if (SavedTower->Tower == 0)
|
|
{
|
|
FreeMem(NewNode);
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
if (fPatchTower)
|
|
{
|
|
PatchTower(SavedTower->Tower, PatchTowerAddress);
|
|
}
|
|
break;
|
|
|
|
case EP_LOOKUP:
|
|
Size = sizeof(SAVED_EPT) + strlen(Node->Annotation) + 1;
|
|
|
|
if ((NewNode = AllocMem(Size)) == 0)
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
|
|
SavedEndpoint = (PSAVED_EPT) NewNode;
|
|
memset(SavedEndpoint, 0, Size);
|
|
SavedEndpoint->Cb = Size;
|
|
SavedEndpoint->Signature = EPLookupSignature;
|
|
SavedEndpoint->Tower = NewTower(Psep->Tower);
|
|
SavedEndpoint->Annotation = (char *)NewNode +
|
|
sizeof(SAVED_EPT);
|
|
memcpy( (char *) &SavedEndpoint->Object,
|
|
(char *)&Node->ObjUuid,
|
|
sizeof(UUID)
|
|
);
|
|
strcpy(SavedEndpoint->Annotation, Node->Annotation);
|
|
|
|
if (SavedEndpoint->Tower == 0)
|
|
{
|
|
FreeMem(NewNode);
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
if (fPatchTower)
|
|
{
|
|
PatchTower(SavedEndpoint->Tower, PatchTowerAddress);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ASSERT(!"Unknown lookup type\n");
|
|
return(RPC_S_INTERNAL_ERROR);
|
|
break;
|
|
|
|
}
|
|
|
|
Link((PIENTRY *)(&Context->List), NewNode);
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
|
|
|
|
RPC_STATUS
|
|
GetEntriesFromSavedContext(
|
|
PSAVEDCONTEXT Context,
|
|
char * Buffer,
|
|
unsigned long Requested,
|
|
unsigned long *Returned
|
|
)
|
|
{
|
|
|
|
PIENTRY SavedEntry = (PIENTRY)Context->List;
|
|
PIENTRY TmpEntry;
|
|
unsigned long Type = Context->Type;
|
|
|
|
while ( (*Returned < Requested) && (SavedEntry != 0) )
|
|
{
|
|
switch (Type)
|
|
{
|
|
case EP_MAP:
|
|
((I_Tower *)Buffer)->Tower = ((PSAVEDTOWER)SavedEntry)->Tower;
|
|
Buffer = Buffer + sizeof(I_Tower);
|
|
break;
|
|
|
|
case EP_LOOKUP:
|
|
((ept_entry_t *)Buffer)->tower = ((PSAVED_EPT)SavedEntry)->Tower;
|
|
strcpy(((ept_entry_t *)Buffer)->annotation,
|
|
((PSAVED_EPT)SavedEntry)->Annotation);
|
|
memcpy(Buffer,(char *)&((PSAVED_EPT)SavedEntry)->Object,
|
|
sizeof(UUID));
|
|
Buffer = Buffer + sizeof(ept_entry_t);
|
|
break;
|
|
|
|
default:
|
|
ASSERT(!"Unknown Inquiry Type");
|
|
break;
|
|
}
|
|
|
|
(*Returned)++;
|
|
TmpEntry = SavedEntry;
|
|
SavedEntry = SavedEntry->Next;
|
|
UnLink((PIENTRY *)&Context->List, TmpEntry);
|
|
FreeMem(TmpEntry);
|
|
}
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
|
|
|
|
RPC_STATUS
|
|
GetEntries(
|
|
UUID *ObjUuid,
|
|
UUID *IFUuid,
|
|
unsigned long Version,
|
|
char * Pseq,
|
|
ept_lookup_handle_t *key,
|
|
char * Buffer,
|
|
unsigned long Calltype,
|
|
unsigned long Requested,
|
|
unsigned long *Returned,
|
|
unsigned long InqType,
|
|
unsigned long VersOptions,
|
|
PFNPointer Match
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is a generic routine for retreiving a series [as spec. by Requested]
|
|
of Towers (in case of Map) or ept_entry_t's in case of Lookup.
|
|
|
|
Arguments:
|
|
|
|
ObjUuid - Object Uuid
|
|
|
|
IfUuid - Interface Uuid
|
|
|
|
Version - InterfaceVersion [hi ushort = VerMajor, lo ushort VerMinor]
|
|
|
|
Protseq - An ascii string specifying the protocol seq.
|
|
|
|
key - A resume key - If NULL, search is started from the beginning
|
|
if non-null, represents an encoding from where the epmapper
|
|
supposed to start searching. It is an opaque value as far
|
|
as the client is concerned.
|
|
|
|
Buffer - A buffer of entries returned
|
|
|
|
Calltype - A flag to indicate whether Ep_entries or string bindings
|
|
are to be returned.
|
|
|
|
Requested - Max no. of entries requested
|
|
|
|
Returned - Actual no of entroes returned
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OUT_OF_MEMORY
|
|
|
|
RPC_S_OK
|
|
|
|
EP_S_NOT_REGISTERED
|
|
|
|
--*/
|
|
{
|
|
PIFOBJNode pNode=NULL, pList = IFObjList;
|
|
unsigned long err=0, fResumeNodeFound=0;
|
|
PPSEPNode pPSEPNode;
|
|
char * buffer = Buffer;
|
|
PSAVEDCONTEXT Context = (PSAVEDCONTEXT) *key;
|
|
ept_lookup_handle_t LOOKUP_FINISHED = (ept_lookup_handle_t) LongToPtr(0xffffffff);
|
|
int UNALIGNED *pIPAddr;
|
|
BOOL fPatchTower;
|
|
int PatchTowerAddress;
|
|
SOCKADDR_STORAGE SockAddr;
|
|
ULONG BufferSize;
|
|
int FormatType;
|
|
RPC_STATUS RpcStatus;
|
|
|
|
*Returned = 0;
|
|
|
|
EnterSem();
|
|
|
|
if (*key)
|
|
{
|
|
if (*key == LOOKUP_FINISHED)
|
|
{
|
|
*key = 0;
|
|
LeaveSem();
|
|
return(EP_S_NOT_REGISTERED);
|
|
}
|
|
|
|
if (Context->Signature != EPLookupHandleSignature)
|
|
{
|
|
LeaveSem();
|
|
return EP_S_CANT_PERFORM_OP;
|
|
}
|
|
|
|
err = GetEntriesFromSavedContext(Context, Buffer, Requested, Returned);
|
|
if (Context->List == 0)
|
|
{
|
|
UnLink((PIENTRY *)&GlobalContextList, (PIENTRY)Context);
|
|
FreeMem(Context);
|
|
|
|
// Setting the Key To FFFFFFFFL is a hack for down level
|
|
// Version 1.0 Ep Clients who never expected getting a key 0
|
|
// and Success!
|
|
if (Requested <= 1)
|
|
*key = LOOKUP_FINISHED;
|
|
else
|
|
*key = 0L;
|
|
|
|
LeaveSem();
|
|
return(err);
|
|
}
|
|
|
|
LeaveSem();
|
|
return(err);
|
|
}
|
|
|
|
*key = 0;
|
|
while ((!err))
|
|
{
|
|
if ((pNode = FindIFOBJNode(
|
|
pList,
|
|
ObjUuid,
|
|
IFUuid,
|
|
Version,
|
|
InqType,
|
|
VersOptions,
|
|
Match)) == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
pPSEPNode = pNode->PSEPlist;
|
|
|
|
while (pPSEPNode != 0)
|
|
{
|
|
if ((pPSEPNode = FindPSEP(pPSEPNode, Pseq, NULL, 0L,
|
|
MatchPSAndEP)) == 0)
|
|
break;
|
|
|
|
fPatchTower = FALSE;
|
|
if (StringCompareA(pPSEPNode->Protseq, "ncacn_ip_tcp") == 0
|
|
|| StringCompareA(pPSEPNode->Protseq, "ncadg_ip_udp") == 0
|
|
|| StringCompareA(pPSEPNode->Protseq, "ncacn_http") == 0)
|
|
{
|
|
pIPAddr = (int UNALIGNED *) ((char *) pPSEPNode->Tower + IP_ADDR_OFFSET);
|
|
|
|
if (*pIPAddr == 0)
|
|
{
|
|
BufferSize = sizeof(SockAddr);
|
|
|
|
RpcStatus = I_RpcServerInqLocalConnAddress(NULL,
|
|
&SockAddr,
|
|
&BufferSize,
|
|
&FormatType);
|
|
|
|
if (RpcStatus == RPC_S_OK)
|
|
{
|
|
// IPv6 towers don't exist yet - they are not defined
|
|
// by DCE. Do patching for IPv4 only
|
|
if (FormatType == RPC_P_ADDR_FORMAT_TCP_IPV4)
|
|
{
|
|
PatchTowerAddress = ((SOCKADDR_IN *)&SockAddr)->sin_addr.S_un.S_addr;
|
|
fPatchTower = TRUE;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
if (*Returned < Requested)
|
|
{
|
|
err = PackDataIntoBuffer(&buffer, pNode, pPSEPNode, Calltype, fPatchTower, PatchTowerAddress);
|
|
if (err == RPC_S_OK)
|
|
{
|
|
(*Returned)++;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(err == RPC_S_OUT_OF_MEMORY);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Context == 0)
|
|
{
|
|
*key = (ept_lookup_handle_t) (Context = GetNewContext(Calltype));
|
|
if (Context == 0)
|
|
{
|
|
err = RPC_S_OUT_OF_MEMORY;
|
|
break;
|
|
}
|
|
}
|
|
AddToSavedContext(Context, pNode, pPSEPNode, Calltype, fPatchTower, PatchTowerAddress);
|
|
}
|
|
|
|
pPSEPNode = pPSEPNode->Next;
|
|
} // while - over PSEPList
|
|
|
|
pList = pNode->Next;
|
|
} // while - over IFOBJList
|
|
|
|
|
|
LeaveSem();
|
|
|
|
if ((*Returned == 0) && Requested && (!err))
|
|
{
|
|
err = EP_S_NOT_REGISTERED;
|
|
}
|
|
|
|
if ((*Returned <= Requested) && (Context == 0))
|
|
{
|
|
if (Requested <= 1)
|
|
*key = LOOKUP_FINISHED;
|
|
else
|
|
*key = 0L;
|
|
}
|
|
|
|
return(err);
|
|
}
|
|
|
|
|
|
|
|
|
|
RPC_STATUS
|
|
PackDataIntoBuffer(
|
|
char * * Buffer,
|
|
PIFOBJNode Node,
|
|
PPSEPNode PSEP,
|
|
unsigned long Type,
|
|
BOOL fPatchTower,
|
|
int PatchTowerAddress
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine copies 1 entry [Either a Tower or ept_entry]
|
|
in the Buffer, increments buffer appropriately.
|
|
|
|
Arguments:
|
|
|
|
BindingHandle - An explicit binding handle to the EP.
|
|
|
|
Node - IFOBJNode
|
|
|
|
PSEP - PSEPNode
|
|
|
|
Type - Type of entry to be copied
|
|
|
|
PatchTower - if TRUE, the newly created tower needs to be patched. If
|
|
FALSE, the tower doesn't need to be patched
|
|
|
|
PatchTowerAddress - an IPv4 representation of the address to be put
|
|
in the tower. The IPv4 address must be in network byte order
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK or RPC_S_* for error
|
|
|
|
--*/
|
|
{
|
|
I_Tower * Twr;
|
|
ept_entry_t *p;
|
|
|
|
switch (Type)
|
|
{
|
|
case EP_MAP:
|
|
Twr = (I_Tower *)(* Buffer);
|
|
Twr->Tower = NewTower(PSEP->Tower);
|
|
if (Twr->Tower == 0)
|
|
{
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
if (fPatchTower)
|
|
PatchTower(Twr->Tower, PatchTowerAddress);
|
|
*Buffer += sizeof(I_Tower);
|
|
break;
|
|
|
|
case EP_LOOKUP:
|
|
p = (ept_entry_t *)(*Buffer);
|
|
p->tower = NewTower(PSEP->Tower);
|
|
if (p->tower == 0)
|
|
{
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
if (fPatchTower)
|
|
PatchTower(p->tower, PatchTowerAddress);
|
|
memcpy( *Buffer, (char *)&Node->ObjUuid, sizeof(UUID) );
|
|
strcpy(p->annotation, Node->Annotation);
|
|
*Buffer += sizeof(ept_entry_t);
|
|
break;
|
|
|
|
default:
|
|
ASSERT(!"Unknown type");
|
|
break;
|
|
}
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
ept_cleanup_handle_t_rundown(
|
|
ept_cleanup_handle_t hEpCleanup
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine cleans up the entries registered by the process
|
|
associated with this context handle hEpCleanup.
|
|
|
|
Arguments:
|
|
|
|
hEpCleanup - The context handle for which the rundown is
|
|
being done.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PIFOBJNode NodesListToDelete = NULL;
|
|
PIFOBJNode pIterator, DeleteMe, pPreviousNode;
|
|
PPSEPNode pTempPSEP, pDeletePSEP;
|
|
PEP_CLEANUP ProcessCtxt = (PEP_CLEANUP) hEpCleanup;
|
|
#ifdef DBG_DETAIL
|
|
PIFOBJNode pTemp, pLast;
|
|
#endif // DBG_DETAIL
|
|
|
|
if (ProcessCtxt == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
EnterSem();
|
|
|
|
ASSERT(IFObjList);
|
|
ASSERT(cTotalEpEntries > 0);
|
|
ASSERT(ProcessCtxt->EntryList);
|
|
ASSERT(ProcessCtxt->cEntries > 0);
|
|
ASSERT(ProcessCtxt->EntryList->OwnerOfList == ProcessCtxt);
|
|
ASSERT_PROCESS_CONTEXT_LIST_COUNT(ProcessCtxt, ProcessCtxt->cEntries);
|
|
|
|
#ifdef DBG_DETAIL
|
|
DbgPrint("RPCSS: Entered Cleanup Rundown for [%p] with (%d) entries\n",
|
|
hEpCleanup, ProcessCtxt->cEntries);
|
|
DbgPrint("RPCSS: Dump of IFOBJList\n");
|
|
pTemp = IFObjList;
|
|
pLast = IFObjList;
|
|
while (pTemp)
|
|
{
|
|
DbgPrint("RPCSS: \t\t[%p]\n", pTemp);
|
|
pLast = pTemp;
|
|
pTemp = pTemp->Next;
|
|
}
|
|
DbgPrint("RPCSS: --------------------\n");
|
|
while (pLast)
|
|
{
|
|
DbgPrint("RPCSS: \t\t\t[%p]\n", pLast);
|
|
pLast = pLast->Prev;
|
|
}
|
|
#endif // DBG_DETAIL
|
|
|
|
// Save the previous Node.
|
|
pPreviousNode = ProcessCtxt->EntryList->Prev;
|
|
|
|
pIterator = ProcessCtxt->EntryList;
|
|
while ((pIterator != NULL) && (pIterator->OwnerOfList == ProcessCtxt))
|
|
{
|
|
ProcessCtxt->cEntries--;
|
|
cTotalEpEntries--;
|
|
#ifdef DBG_DETAIL
|
|
DbgPrint("RPCSS: cTotalEpEntries-- [%p] (%d) - Cleanup\n", hEpCleanup, cTotalEpEntries);
|
|
#endif // DBG_DETAIL
|
|
|
|
DeleteMe = pIterator;
|
|
pIterator = pIterator->Next;
|
|
|
|
// Add to a list that will be deleted later.
|
|
DeleteMe->Next = NodesListToDelete;
|
|
}
|
|
|
|
ASSERT(ProcessCtxt->cEntries == 0);
|
|
|
|
//
|
|
// Adjust the links
|
|
//
|
|
if (pPreviousNode)
|
|
{
|
|
// Adjust forward link
|
|
pPreviousNode->Next = pIterator;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(ProcessCtxt->EntryList == IFObjList);
|
|
}
|
|
|
|
if (pIterator)
|
|
{
|
|
// Adjust backward link
|
|
pIterator->Prev = pPreviousNode;
|
|
}
|
|
|
|
//
|
|
// Empty the EP Mapper table, if necessary.
|
|
//
|
|
if (ProcessCtxt->EntryList == IFObjList)
|
|
{
|
|
if (pIterator)
|
|
{
|
|
ASSERT(cTotalEpEntries > 0);
|
|
|
|
// New Head for Ep Mapper list
|
|
IFObjList = pIterator;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(cTotalEpEntries == 0);
|
|
|
|
// Memory for this node is already freed in the while loop above.
|
|
IFObjList = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASSERT(cTotalEpEntries > 0);
|
|
}
|
|
|
|
LeaveSem();
|
|
|
|
//
|
|
// Free entities outside the lock.
|
|
//
|
|
FreeMem(ProcessCtxt);
|
|
|
|
while (NodesListToDelete != NULL)
|
|
{
|
|
DeleteMe = NodesListToDelete;
|
|
NodesListToDelete = NodesListToDelete->Next;
|
|
// Delete the PSEP list.
|
|
pTempPSEP = DeleteMe->PSEPlist;
|
|
while (pTempPSEP != NULL)
|
|
{
|
|
pDeletePSEP = pTempPSEP;
|
|
pTempPSEP = pTempPSEP->Next;
|
|
FreeMem(pDeletePSEP);
|
|
}
|
|
FreeMem(DeleteMe);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
ept_insert(
|
|
handle_t h,
|
|
unsigned32 NumEntries,
|
|
ept_entry_t Entries[],
|
|
unsigned long Replace,
|
|
error_status *Status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is no longer supported by EpMapper. RPC Runtime does not
|
|
call this function anymore. And, no one else should be...
|
|
|
|
--*/
|
|
{
|
|
ASSERT(Status);
|
|
|
|
*Status = EPT_S_CANT_PERFORM_OP;
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
ept_insert_ex(
|
|
IN handle_t h,
|
|
IN OUT ept_cleanup_handle_t *hEpCleanup,
|
|
IN unsigned32 NumEntries,
|
|
IN ept_entry_t Entries[],
|
|
IN unsigned long Replace,
|
|
OUT error_status *Status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the exposed rpc interface routine that adds a series of
|
|
endpoints to the Endpoint Mapper database.
|
|
|
|
Arguments:
|
|
|
|
h - An explicit binding handle to the EP.
|
|
|
|
hEpCleanup - A context handle used to purge the Endpoint Mapper
|
|
database of stale entries.
|
|
|
|
NumEntries - Number of Entries to be added.
|
|
|
|
Entries - An array of ept_entry_t entries.
|
|
|
|
Replace - TRUE => Replace existing entries.
|
|
FALSE=> Just add.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - The endpoint was successfully deleted.
|
|
|
|
RPC_S_OUT_OF_MEMORY - There is no memory to perform the op.
|
|
|
|
EPT_S_CANT_PERFORM - Invalid entry.
|
|
|
|
--*/
|
|
{
|
|
ept_entry_t * Ep;
|
|
unsigned short i, j;
|
|
unsigned int TransType = 0x0;
|
|
unsigned long err = 0;
|
|
unsigned long Version;
|
|
unsigned char protseqid;
|
|
char *Protseq, *Endpoint;
|
|
RPC_IF_ID IfId;
|
|
PPSEPNode List = 0;
|
|
PPSEPNode pPSEPNode, TmpPsep, pTempPSEP, pDeletePSEP;
|
|
unsigned long cb;
|
|
twr_t * Tower;
|
|
BOOL bIFNodeFound = FALSE;
|
|
PIFOBJNode NodesListToDelete = NULL;
|
|
PIFOBJNode Node, NewNode, DeleteMe = NULL;
|
|
UUID * Object;
|
|
char * Annotation;
|
|
RPC_STATUS Err;
|
|
SECURITY_DESCRIPTOR SecurityDescriptor, * PSecurityDesc;
|
|
BOOL Bool;
|
|
|
|
//
|
|
// First, make sure the call is via LRPC.
|
|
//
|
|
err = I_RpcBindingInqTransportType(h, &TransType);
|
|
ASSERT(err == RPC_S_OK);
|
|
|
|
if (TransType != TRANSPORT_TYPE_LPC)
|
|
{
|
|
*Status = RPC_S_ACCESS_DENIED;
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// Create a temporary PSEP list from the Tower entries.
|
|
//
|
|
for (Ep = &Entries[0], i = 0; i < NumEntries; Ep++,i++)
|
|
{
|
|
err = TowerExplode(
|
|
Ep->tower,
|
|
&IfId,
|
|
NULL,
|
|
&Protseq,
|
|
&Endpoint,
|
|
0
|
|
);
|
|
|
|
if (err == RPC_S_OUT_OF_MEMORY)
|
|
break;
|
|
|
|
if (err)
|
|
{
|
|
err = RPC_S_OK;
|
|
continue;
|
|
}
|
|
|
|
Object = &Ep->object;
|
|
Annotation = (char *)&Ep->annotation;
|
|
Tower = Ep->tower;
|
|
|
|
cb = sizeof(PSEPNode) +
|
|
strlen(Protseq) +
|
|
strlen(Endpoint) +
|
|
2 + // for the 2 null terminators
|
|
Tower->tower_length +
|
|
sizeof(Tower->tower_length) +
|
|
4; // We need to align tower on DWORD
|
|
|
|
if ( (pPSEPNode = AllocMem(cb)) == NULL )
|
|
{
|
|
err = RPC_S_OUT_OF_MEMORY;
|
|
break;
|
|
}
|
|
|
|
// Mark this protseq to start listening if needed.
|
|
protseqid = (unsigned char) GetProtseqIdAnsi(Protseq);
|
|
DelayedUseProtseq(protseqid);
|
|
|
|
//
|
|
// Add a node to the temporary PSEP list
|
|
//
|
|
memset(pPSEPNode, 0, cb);
|
|
|
|
pPSEPNode->Signature = PSEPSIGN;
|
|
pPSEPNode->Cb = cb;
|
|
|
|
//strcpy(pPSEPNode->Protseq= ((char *) (pPSEPNode+1)), Protseq);
|
|
// Protseq
|
|
pPSEPNode->Protseq = (char *) (pPSEPNode + 1); // What is the +1 for?
|
|
strcpy(pPSEPNode->Protseq, Protseq);
|
|
|
|
// Endpoint
|
|
pPSEPNode->EP = pPSEPNode->Protseq + strlen(pPSEPNode->Protseq) + 1;
|
|
strcpy(pPSEPNode->EP, Endpoint);
|
|
|
|
// Tower. We add necessary pad so that Tower is aligned to a DWORD.
|
|
pPSEPNode->Tower = (twr_t PAPI *)(pPSEPNode->EP +
|
|
strlen(pPSEPNode->EP) + 1);
|
|
(char PAPI*)(pPSEPNode->Tower) += 4 - ((ULONG_PTR)
|
|
(pPSEPNode->Tower) & 3);
|
|
memcpy((char PAPI *)pPSEPNode->Tower,
|
|
Tower,
|
|
Tower->tower_length + sizeof(Tower->tower_length)
|
|
);
|
|
|
|
// Finally, add.
|
|
EnterSem();
|
|
EnLinkOnPSEPList(&List, pPSEPNode);
|
|
LeaveSem();
|
|
|
|
I_RpcFree(Protseq);
|
|
I_RpcFree(Endpoint);
|
|
}
|
|
|
|
if ((err == RPC_S_OUT_OF_MEMORY) || (List == 0))
|
|
{
|
|
*Status = err;
|
|
return;
|
|
}
|
|
|
|
|
|
CompleteDelayedUseProtseqs();
|
|
|
|
|
|
Version = VERSION(IfId.VersMajor, IfId.VersMinor);
|
|
|
|
//
|
|
// Find if a compatible Endpoint Mapper entry is already present.
|
|
//
|
|
|
|
if (*hEpCleanup != NULL)
|
|
{
|
|
//
|
|
// The requesting process has previously registered entries
|
|
// with the Endpoint Mapper.
|
|
//
|
|
|
|
ASSERT_PROCESS_CONTEXT_LIST_COUNT((PEP_CLEANUP)*hEpCleanup, ((PEP_CLEANUP)*hEpCleanup)->cEntries);
|
|
ASSERT(((PEP_CLEANUP)*hEpCleanup)->MagicVal == CLEANUP_MAGIC_VALUE);
|
|
ASSERT(((PEP_CLEANUP)*hEpCleanup)->cEntries != 0);
|
|
|
|
if ( (((PEP_CLEANUP)*hEpCleanup)->MagicVal != CLEANUP_MAGIC_VALUE)
|
|
|| (((PEP_CLEANUP)*hEpCleanup)->cEntries == 0))
|
|
{
|
|
*Status = EPT_S_CANT_PERFORM_OP;
|
|
return;
|
|
}
|
|
|
|
EnterSem();
|
|
|
|
if (Replace == TRUE) // Common case
|
|
{
|
|
//
|
|
// If we find a compatible entry, we just replace its PSEP list
|
|
// with the temporary list that we just created.
|
|
//
|
|
Node = ((PEP_CLEANUP)*hEpCleanup)->EntryList;
|
|
|
|
while (Node != 0)
|
|
{
|
|
Node = FindIFOBJNode(
|
|
Node,
|
|
Object,
|
|
&IfId.Uuid,
|
|
Version,
|
|
RPC_C_EP_MATCH_BY_BOTH,
|
|
I_RPC_C_VERS_UPTO_AND_COMPATIBLE,
|
|
SearchIFObjNode
|
|
);
|
|
|
|
if ((Node == 0) || (Node->OwnerOfList != *hEpCleanup))
|
|
break;
|
|
|
|
// Matching Endpoint Mapper entry found.
|
|
|
|
PurgeOldEntries(Node, List, FALSE);
|
|
|
|
if (Node->IFVersion == Version)
|
|
{
|
|
bIFNodeFound = TRUE;
|
|
|
|
// Seek to the end of Tmp and then Link
|
|
TmpPsep = List;
|
|
while (TmpPsep->Next != 0)
|
|
TmpPsep = TmpPsep->Next;
|
|
|
|
TmpPsep->Next = Node->PSEPlist;
|
|
Node->PSEPlist = List;
|
|
}
|
|
|
|
if (Node->PSEPlist == 0)
|
|
{
|
|
DeleteMe = Node;
|
|
Node = Node->Next;
|
|
err = UnLinkFromIFOBJList((PEP_CLEANUP)*hEpCleanup, DeleteMe);
|
|
ASSERT(err == RPC_S_OK);
|
|
|
|
// Add to a list that will be deleted later...
|
|
DeleteMe->Next = NodesListToDelete;
|
|
NodesListToDelete = DeleteMe;
|
|
|
|
DeleteMe->Signature = FREE;
|
|
}
|
|
else
|
|
{
|
|
Node = Node->Next;
|
|
}
|
|
} // while loop
|
|
}
|
|
else // (Replace != TRUE)
|
|
{
|
|
//
|
|
// If we find an entry with an exact match, we append
|
|
// the temporary PSEP list to the entry's PSEP list.
|
|
//
|
|
Node = ((PEP_CLEANUP)*hEpCleanup)->EntryList;
|
|
|
|
NewNode = FindIFOBJNode(
|
|
Node,
|
|
Object,
|
|
&IfId.Uuid,
|
|
Version,
|
|
0,
|
|
0,
|
|
ExactMatch
|
|
);
|
|
|
|
if (NewNode && (NewNode->OwnerOfList == *hEpCleanup))
|
|
{
|
|
bIFNodeFound = TRUE;
|
|
|
|
PurgeOldEntries(NewNode, List, TRUE);
|
|
|
|
// Seek to the end of Tmp and then Link
|
|
TmpPsep = List;
|
|
while (TmpPsep->Next != 0)
|
|
TmpPsep = TmpPsep->Next;
|
|
|
|
TmpPsep->Next = NewNode->PSEPlist;
|
|
NewNode->PSEPlist = List;
|
|
}
|
|
} // if (Replace == TRUE)
|
|
|
|
LeaveSem();
|
|
|
|
} // if (*hpCleanup != NULL)
|
|
|
|
|
|
//
|
|
// Free the list outside the lock.
|
|
//
|
|
while (NodesListToDelete != NULL)
|
|
{
|
|
DeleteMe = NodesListToDelete;
|
|
NodesListToDelete = NodesListToDelete->Next;
|
|
// Delete the PSEP list.
|
|
pTempPSEP = DeleteMe->PSEPlist;
|
|
while (pTempPSEP != NULL)
|
|
{
|
|
pDeletePSEP = pTempPSEP;
|
|
pTempPSEP = pTempPSEP->Next;
|
|
FreeMem(pDeletePSEP);
|
|
}
|
|
FreeMem(DeleteMe);
|
|
}
|
|
|
|
if (bIFNodeFound == FALSE)
|
|
{
|
|
//
|
|
// One of the following is TRUE:
|
|
// a. The process is registering with EP Mapper for the first time.
|
|
// b. No compatible Ep entry was found.
|
|
//
|
|
|
|
//
|
|
// Allocate a new EP Mapper entry.
|
|
//
|
|
cb = sizeof(IFOBJNode);
|
|
cb += strlen(Annotation) + 1;
|
|
if ((NewNode = AllocMem(cb)) == NULL)
|
|
{
|
|
*Status = RPC_S_OUT_OF_MEMORY;
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Fill-in the new entry
|
|
//
|
|
memset(NewNode, 0, cb);
|
|
|
|
NewNode->Cb = cb;
|
|
NewNode->Signature = IFOBJSIGN;
|
|
NewNode->IFVersion = Version;
|
|
|
|
memcpy((char *)&NewNode->ObjUuid, (char *)Object, sizeof(UUID));
|
|
memcpy((char *)&NewNode->IFUuid, (char *)&IfId.Uuid, sizeof(UUID));
|
|
strcpy((NewNode->Annotation=(char *)(NewNode+1)), Annotation);
|
|
|
|
if (IsNullUuid(Object))
|
|
NewNode->IFOBJid = MAKEGLOBALIFOBJID(MAXIFOBJID);
|
|
else
|
|
NewNode->IFOBJid = MAKEGLOBALIFOBJID(GlobalIFOBJid--);
|
|
|
|
//
|
|
// Create a new context for this process, if necessary
|
|
//
|
|
if (*hEpCleanup == NULL)
|
|
{
|
|
*hEpCleanup = AllocMem(sizeof(EP_CLEANUP));
|
|
if (*hEpCleanup == NULL)
|
|
{
|
|
LeaveSem();
|
|
FreeMem(NewNode);
|
|
*Status = RPC_S_OUT_OF_MEMORY;
|
|
return;
|
|
}
|
|
|
|
memset(*hEpCleanup, 0x0, sizeof(EP_CLEANUP));
|
|
|
|
((PEP_CLEANUP)*hEpCleanup)->MagicVal = CLEANUP_MAGIC_VALUE;
|
|
}
|
|
|
|
//
|
|
// Insert the new entry into the EP Mapper table.
|
|
//
|
|
EnterSem();
|
|
|
|
err = EnLinkOnIFOBJList((PEP_CLEANUP)*hEpCleanup, NewNode);
|
|
ASSERT(err == RPC_S_OK);
|
|
|
|
NewNode->PSEPlist = List;
|
|
|
|
LeaveSem();
|
|
}
|
|
|
|
*Status = err;
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
ept_delete(
|
|
handle_t h,
|
|
unsigned32 NumEntries,
|
|
ept_entry_t Entries[],
|
|
error_status *Status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is no longer supported by EpMapper. RPC Runtime does not
|
|
call this function anymore. And, no one else should be...
|
|
|
|
--*/
|
|
{
|
|
ASSERT(Status);
|
|
|
|
*Status = EPT_S_CANT_PERFORM_OP;
|
|
}
|
|
|
|
|
|
|
|
|
|
RPC_STATUS
|
|
ept_delete_ex_helper(
|
|
IN ept_cleanup_handle_t hEpCleanup,
|
|
IN UUID *Object,
|
|
IN UUID *Interface,
|
|
IN unsigned long IFVersion,
|
|
IN char PAPI * Protseq,
|
|
IN char PAPI * Endpoint
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine deletes an Endpoint registered with the EP Mapper
|
|
|
|
Arguments:
|
|
|
|
hEpCleanup - A context handle used to purge the Endpoint Mapper
|
|
database of stale entries.
|
|
|
|
Object - Object Uuid.
|
|
|
|
Interface - If Uuid
|
|
|
|
IFVersion - Version of the IF [Hi ushort=Major, Lo ushort=Minor]
|
|
|
|
Protseq - Protocol Sequence
|
|
|
|
Endpoint - Endpoint string
|
|
|
|
Notes:
|
|
|
|
a. This routine has to be called by holding a mutex.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - The endpoint was successfully deleted
|
|
|
|
EPT_S_NOT_REGISTERED - No matching entries were found
|
|
|
|
--*/
|
|
{
|
|
PIFOBJNode pNode;
|
|
PPSEPNode pPSEPNode = NULL;
|
|
unsigned long cb, err = 0;
|
|
PEP_T p;
|
|
PEP_CLEANUP ProcessCtx;
|
|
|
|
if (!Protseq || !Endpoint)
|
|
{
|
|
return(EPT_S_NOT_REGISTERED);
|
|
}
|
|
|
|
CheckInSem();
|
|
|
|
ProcessCtx = (PEP_CLEANUP)hEpCleanup;
|
|
|
|
if (ProcessCtx->EntryList == NULL)
|
|
return EPT_S_NOT_REGISTERED;
|
|
|
|
pNode = FindIFOBJNode(
|
|
ProcessCtx->EntryList,
|
|
Object,
|
|
Interface,
|
|
IFVersion,
|
|
0L,
|
|
0L,
|
|
ExactMatch
|
|
);
|
|
|
|
if ((pNode != NULL) && (pNode->PSEPlist != NULL))
|
|
{
|
|
pPSEPNode = FindPSEP(
|
|
pNode->PSEPlist,
|
|
Protseq,
|
|
Endpoint,
|
|
0L,
|
|
MatchPSAndEP
|
|
);
|
|
}
|
|
|
|
if (pPSEPNode != NULL)
|
|
{
|
|
UnLinkFromPSEPList(&pNode->PSEPlist, pPSEPNode);
|
|
|
|
if (pNode->PSEPlist == NULL)
|
|
{
|
|
err = UnLinkFromIFOBJList((PEP_CLEANUP)hEpCleanup, pNode);
|
|
// ASSERT(err == RPC_S_OK);
|
|
|
|
if (err != RPC_S_OK)
|
|
{
|
|
// Restore the PSEPList
|
|
EnLinkOnPSEPList(&pNode->PSEPlist, pPSEPNode);
|
|
return err;
|
|
}
|
|
|
|
pNode->Signature = FREE;
|
|
FreeMem(pNode);
|
|
}
|
|
|
|
pPSEPNode->Signature = FREE;
|
|
FreeMem(pPSEPNode);
|
|
}
|
|
else
|
|
{
|
|
err = EPT_S_NOT_REGISTERED;
|
|
}
|
|
|
|
return(err);
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
ept_delete_ex(
|
|
IN handle_t h,
|
|
IN OUT ept_cleanup_handle_t *hEpCleanup,
|
|
IN unsigned32 NumEntries,
|
|
IN ept_entry_t Entries[],
|
|
OUT error_status *Status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine deletes the specified Endpoints
|
|
|
|
Arguments:
|
|
|
|
BindingHandle - An explicit binding handle to the EP.
|
|
|
|
NumEntries - #of entries in the Bunffer that need to be deleted.
|
|
|
|
Entries[] - Buffer of #NumEntries of ept_entry_t structures
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - The endpoint was successfully deleted
|
|
|
|
EPT_S_NOT_REGISTERED - No matching entries were found
|
|
|
|
--*/
|
|
{
|
|
ept_entry_t * Ep;
|
|
unsigned short i;
|
|
unsigned int TransType = 0x0;
|
|
RPC_STATUS err;
|
|
RPC_STATUS DeleteStatus;
|
|
unsigned long Version;
|
|
char *Protseq, *Endpoint;
|
|
RPC_IF_ID IfId;
|
|
RPC_TRANSFER_SYNTAX XferId;
|
|
|
|
//
|
|
// First, make sure the call is via LRPC.
|
|
//
|
|
err = I_RpcBindingInqTransportType(h, &TransType);
|
|
ASSERT(err == RPC_S_OK);
|
|
|
|
if (TransType != TRANSPORT_TYPE_LPC)
|
|
{
|
|
*Status = RPC_S_ACCESS_DENIED;
|
|
return;
|
|
}
|
|
|
|
if ( !( (*hEpCleanup)
|
|
&& (((PEP_CLEANUP)*hEpCleanup)->MagicVal == CLEANUP_MAGIC_VALUE)
|
|
&& (((PEP_CLEANUP)*hEpCleanup)->cEntries != 0)
|
|
)
|
|
)
|
|
{
|
|
//
|
|
// Cannot ASSERT here. This is possible. (ep1-26, ep2-3)
|
|
//
|
|
|
|
//ASSERT(*hEpCleanup);
|
|
//ASSERT(((PEP_CLEANUP)*hEpCleanup)->MagicVal == CLEANUP_MAGIC_VALUE);
|
|
//ASSERT(((PEP_CLEANUP)*hEpCleanup)->cEntries != 0);
|
|
|
|
*Status = EPT_S_CANT_PERFORM_OP;
|
|
return;
|
|
}
|
|
|
|
*Status = EPT_S_NOT_REGISTERED;
|
|
DeleteStatus = RPC_S_OK;
|
|
|
|
for (Ep = &Entries[0], i = 0; i < NumEntries; Ep++,i++)
|
|
{
|
|
err = TowerExplode(
|
|
Ep->tower,
|
|
&IfId,
|
|
&XferId,
|
|
&Protseq,
|
|
&Endpoint,
|
|
0
|
|
);
|
|
|
|
if (err == RPC_S_OUT_OF_MEMORY)
|
|
{
|
|
*Status = RPC_S_OUT_OF_MEMORY;
|
|
break;
|
|
}
|
|
|
|
if (err)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
Version = VERSION(IfId.VersMajor, IfId.VersMinor);
|
|
|
|
EnterSem();
|
|
|
|
//
|
|
// NOTE:
|
|
//
|
|
// If even one call to ept_delete_ex_helper() fails, we want to return
|
|
// failure from ept_delete_ex(). This is different from the past where
|
|
// if one call succeeded, then the function returned success.
|
|
//
|
|
err = ept_delete_ex_helper(
|
|
*hEpCleanup,
|
|
&Ep->object,
|
|
&IfId.Uuid,
|
|
Version,
|
|
Protseq,
|
|
Endpoint
|
|
);
|
|
|
|
if (err)
|
|
{
|
|
// Save the last failure status.
|
|
DeleteStatus = err;
|
|
}
|
|
|
|
if (((PEP_CLEANUP)*hEpCleanup)->cEntries == 0)
|
|
{
|
|
//
|
|
// No entry left in this process's list. Time to zero out this
|
|
// process's context handle.
|
|
//
|
|
//ASSERT(((PEP_CLEANUP)*hEpCleanup)->EntryList == NULL);
|
|
|
|
FreeMem(*hEpCleanup);
|
|
*hEpCleanup = NULL;
|
|
}
|
|
|
|
LeaveSem();
|
|
|
|
if (Protseq)
|
|
I_RpcFree(Protseq);
|
|
|
|
if (Endpoint)
|
|
I_RpcFree(Endpoint);
|
|
}
|
|
|
|
if (err)
|
|
{
|
|
// RPC_S_OUT_OF_MEMORY OR the last call to
|
|
// ept_delete_ex_helper() failed.
|
|
*Status = err;
|
|
}
|
|
else
|
|
{
|
|
// RPC_S_OK OR one of the calls to ept_delete_ex_helper() (but
|
|
// not the last one) failed.
|
|
*Status = DeleteStatus;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
ept_lookup(
|
|
handle_t hEpMapper,
|
|
unsigned32 InquiryType,
|
|
UUID * Object,
|
|
RPC_IF_ID * Ifid,
|
|
unsigned32 VersOptions,
|
|
ept_lookup_handle_t *LookupHandle,
|
|
unsigned32 MaxRequested,
|
|
unsigned32 *NumEntries,
|
|
ept_entry_t Entries[],
|
|
error_status *Status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns upto MaxRequested, ept_entry(s) currently
|
|
registered with the Endpoint mapper based on the
|
|
Obj, Interface, Protocol sequence and filters VersOptions and
|
|
InqType
|
|
|
|
Arguments:
|
|
|
|
BindingHandle - An explicit binding handle to the EP.
|
|
|
|
InquiryType - Search Filter [Seach based on IF, Obj or Both]
|
|
|
|
Obj - Object Uuid. specified by the client
|
|
|
|
ObjInterface - Interface Uuid spec. by the client.
|
|
|
|
InId - The If Specification [IF Uuid+IfVersion]
|
|
|
|
VersOpts- Search Filter based on Versions [Versins <, >, ==]
|
|
|
|
MapHandle - A resume key - If NULL, search is started from the beginning
|
|
if non-null, represents an encoding from where the epmapper is
|
|
is supposed to start searching. It is an opaque value as far as the
|
|
as far as the client is concerned.
|
|
|
|
MaxRequested - Max number of entries requested by the client.
|
|
|
|
Returned - The actual number of entries returned by the mapper.
|
|
|
|
Entries - Buffer of ept_entries returned.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OUT_OF_MEMORY
|
|
|
|
RPC_S_OK - At least one matching entry is being returned.
|
|
|
|
EP_S_NOT_REGISTERED - No matching entries were found
|
|
|
|
EPT_S_CANT_PERFORM_OP - MaxRequested value exceed ep_max_lookup_results
|
|
|
|
--*/
|
|
|
|
{
|
|
unsigned long Version;
|
|
|
|
if (Ifid == NULL)
|
|
{
|
|
Ifid = &LocalNullUuid;
|
|
}
|
|
|
|
if (Object == NULL)
|
|
{
|
|
Object = (UUID *) &LocalNullUuid;
|
|
}
|
|
|
|
switch (VersOptions)
|
|
{
|
|
case RPC_C_VERS_ALL:
|
|
Version = 0;
|
|
break;
|
|
|
|
case RPC_C_VERS_COMPATIBLE:
|
|
case RPC_C_VERS_EXACT:
|
|
case RPC_C_VERS_UPTO:
|
|
Version = VERSION(Ifid->VersMajor, Ifid->VersMinor);
|
|
break;
|
|
|
|
case RPC_C_VERS_MAJOR_ONLY:
|
|
Version = VERSION(Ifid->VersMajor, 0);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
*Status = GetEntries(
|
|
Object,
|
|
&Ifid->Uuid,
|
|
Version,
|
|
NULL,
|
|
LookupHandle,
|
|
(char *)Entries,
|
|
EP_LOOKUP,
|
|
MaxRequested,
|
|
NumEntries,
|
|
InquiryType,
|
|
VersOptions,
|
|
SearchIFObjNode
|
|
);
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
ept_map(
|
|
handle_t h,
|
|
UUID *Obj OPTIONAL,
|
|
twr_p_t MapTower,
|
|
ept_lookup_handle_t *MapHandle,
|
|
unsigned32 MaxTowers,
|
|
unsigned32 *NumTowers,
|
|
twr_p_t *ITowers,
|
|
error_status *Status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns a fully-resolved string binding, for a given
|
|
Obj, Interface, and Protocol sequence if an appropriate entry is
|
|
found. Else returns EP_S_NOT_REGISTERED.
|
|
|
|
Arguments:
|
|
|
|
BindingHandle - An explicit binding handle to the EP.
|
|
|
|
Obj - Object Uuid. specified by the client
|
|
|
|
ObjInterface - Interface Uuid spec. by the client.
|
|
|
|
Interfacever - InterfaceVersion [hi ushort = VerMajor, lo ushort VerMinor]
|
|
|
|
Protseq - An ascii string specifying the protocol seq.
|
|
|
|
MapHandle - A resume key - If NULL, search is started from the beginning
|
|
if non-null, represents an encoding from where the epmapper is
|
|
supposed to start searching. It is an opaque value as far as the
|
|
client is concerned.
|
|
|
|
Binding - The fully resolved string binding returned if the call is
|
|
successful.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OUT_OF_MEMORY
|
|
|
|
RPC_S_OK
|
|
|
|
EP_S_NOT_REGISTERED
|
|
|
|
--*/
|
|
{
|
|
RPC_IF_ID Ifid;
|
|
RPC_TRANSFER_SYNTAX Xferid;
|
|
char *Protseq;
|
|
unsigned long Version;
|
|
char * String = 0;
|
|
|
|
if (Obj == 0)
|
|
{
|
|
Obj = (UUID *) &LocalNullUuid;
|
|
}
|
|
|
|
*Status = TowerExplode(
|
|
MapTower,
|
|
&Ifid,
|
|
&Xferid,
|
|
&Protseq,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if (*Status)
|
|
{
|
|
*NumTowers = 0;
|
|
return;
|
|
}
|
|
|
|
Version = VERSION(Ifid.VersMajor,Ifid.VersMinor);
|
|
|
|
if (memcmp((char *)&Ifid.Uuid, (char *)&MgmtIf, sizeof(UUID)) == 0)
|
|
{
|
|
if ((Obj == 0) || IsNullUuid(Obj))
|
|
{
|
|
*NumTowers = 0;
|
|
*Status = RPC_S_BINDING_INCOMPLETE;
|
|
}
|
|
else
|
|
{
|
|
*Status = GetEntries(
|
|
Obj,
|
|
&Ifid.Uuid,
|
|
Version,
|
|
Protseq,
|
|
MapHandle,
|
|
(char *)ITowers,
|
|
EP_MAP,
|
|
MaxTowers,
|
|
NumTowers,
|
|
RPC_C_EP_MATCH_BY_OBJ,
|
|
RPC_C_VERS_ALL,
|
|
SearchIFObjNode
|
|
);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*Status = GetEntries(
|
|
Obj,
|
|
&Ifid.Uuid,
|
|
Version,
|
|
Protseq,
|
|
MapHandle,
|
|
(char *)ITowers,
|
|
EP_MAP,
|
|
MaxTowers,
|
|
NumTowers,
|
|
0L,
|
|
0L,
|
|
WildCardMatch
|
|
);
|
|
}
|
|
|
|
if (Protseq)
|
|
I_RpcFree(Protseq);
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
ept_inq_object(
|
|
handle_t BindingHandle,
|
|
UUID *Object,
|
|
error_status *status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Not supported
|
|
|
|
Arguments:
|
|
|
|
BindingHandle - An explicit binding handle to the EP.
|
|
|
|
Object _ No idea whose UUID this is.
|
|
|
|
Return Value:
|
|
|
|
EPT_S_CANT_PERFORM_OP
|
|
|
|
--*/
|
|
{
|
|
ASSERT(*status);
|
|
|
|
*status = EPT_S_CANT_PERFORM_OP;
|
|
}
|
|
|
|
|
|
|
|
void
|
|
DeletePSEP(
|
|
PIFOBJNode Node,
|
|
char * Protseq,
|
|
char * Endpoint
|
|
)
|
|
{
|
|
|
|
PSEPNode *Psep, *Tmp;
|
|
|
|
if (Node == 0)
|
|
return;
|
|
|
|
Psep = Node->PSEPlist;
|
|
|
|
while (Psep != 0)
|
|
{
|
|
Psep = FindPSEP(
|
|
Psep,
|
|
Protseq,
|
|
Endpoint,
|
|
0L,
|
|
MatchPSAndEP
|
|
);
|
|
|
|
if (Psep != 0)
|
|
{
|
|
Tmp = Psep;
|
|
Psep = Psep->Next;
|
|
UnLinkFromPSEPList(&Node->PSEPlist, Tmp);
|
|
Tmp->Signature = FREE;
|
|
FreeMem(Tmp);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
ept_mgmt_delete(
|
|
handle_t BindingHandle,
|
|
boolean32 ObjectSpecd,
|
|
UUID * Object,
|
|
twr_p_t Tower,
|
|
error_status *Error
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Not supported
|
|
|
|
Arguments:
|
|
|
|
BindingHandle - An explicit binding handle to the EP.
|
|
|
|
Object _ ObjUUid
|
|
|
|
Tower - Tower specifying the Endpoints to be deleted.
|
|
|
|
Return Value:
|
|
|
|
EPT_S_CANT_PERFORM_OP
|
|
|
|
--*/
|
|
{
|
|
ASSERT(*Error);
|
|
|
|
*Error = EP_S_CANT_PERFORM_OP;
|
|
}
|
|
|
|
|
|
|
|
|
|
void ept_lookup_handle_t_rundown (ept_lookup_handle_t h)
|
|
{
|
|
|
|
PSAVEDCONTEXT Context = (PSAVEDCONTEXT) h;
|
|
PIENTRY Entry;
|
|
unsigned long Type;
|
|
PIENTRY Tmp;
|
|
twr_t * Tower;
|
|
|
|
|
|
ASSERT (Context != 0);
|
|
|
|
if ( (PtrToUlong(Context)) == 0xFFFFFFFF)
|
|
return;
|
|
|
|
Type = Context->Type;
|
|
|
|
EnterSem();
|
|
|
|
Entry = (PIENTRY)Context->List;
|
|
|
|
while (Entry != 0)
|
|
{
|
|
switch (Type)
|
|
{
|
|
case EP_MAP:
|
|
Tower = ((PSAVEDTOWER)Entry)->Tower;
|
|
break;
|
|
|
|
case EP_LOOKUP:
|
|
Tower = ((PSAVED_EPT)Entry)->Tower;
|
|
break;
|
|
|
|
default:
|
|
ASSERT(!"Unknown Inquiry Type");
|
|
break;
|
|
}
|
|
|
|
MIDL_user_free(Tower);
|
|
Tmp = Entry;
|
|
Entry = Entry->Next;
|
|
FreeMem(Tmp);
|
|
}
|
|
|
|
// Now free The Context
|
|
UnLink((PIENTRY *)&GlobalContextList, (PIENTRY)Context);
|
|
|
|
LeaveSem();
|
|
|
|
FreeMem(Context);
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
ept_lookup_handle_free(
|
|
handle_t h,
|
|
ept_lookup_handle_t * ept_context_handle,
|
|
error_status * status
|
|
)
|
|
{
|
|
if ( (ept_context_handle != 0) && (*ept_context_handle != 0))
|
|
{
|
|
ept_lookup_handle_t_rundown( *ept_context_handle );
|
|
*ept_context_handle = 0;
|
|
}
|
|
|
|
*status = 0;
|
|
}
|
|
|
|
|
|
|
|
#define MAX(x,y) ((x) < (y)) ? (y) : (x)
|
|
#define MIN(x,y) ((x) > (y)) ? (y) : (x)
|
|
|
|
#ifdef DEBUGRPC
|
|
#define DEBUG_MIN(x,y) MIN((x),(y))
|
|
#else
|
|
#define DEBUG_MIN(x,y) MAX((x),(y))
|
|
#endif
|
|
|
|
|
|
|
|
|
|
error_status_t
|
|
OpenEndpointMapper(
|
|
IN handle_t hServer,
|
|
OUT HPROCESS *pProcessHandle
|
|
)
|
|
{
|
|
PROCESS *pProcess = MIDL_user_allocate(sizeof(PROCESS));
|
|
|
|
if (!pProcess)
|
|
{
|
|
*pProcessHandle = 0;
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
pProcess->MagicVal = PROCESS_MAGIC_VALUE;
|
|
pProcess->pPorts = 0;
|
|
*pProcessHandle = (PVOID)pProcess;
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Port Management stuff
|
|
//
|
|
|
|
|
|
|
|
//
|
|
// Port Management Globals
|
|
//
|
|
|
|
const RPC_CHAR *PortConfigKey = RPC_CONST_STRING("Software\\Microsoft\\Rpc\\Internet");
|
|
const RPC_CHAR *DefaultPortType = RPC_CONST_STRING("UseInternetPorts");
|
|
const RPC_CHAR *ExplictPortType = RPC_CONST_STRING("PortsInternetAvailable");
|
|
const RPC_CHAR *PortRanges = RPC_CONST_STRING("Ports");
|
|
|
|
CRITICAL_SECTION PortLock;
|
|
|
|
BOOL fValidConfiguration = FALSE;
|
|
BOOL fPortRestrictions = FALSE;
|
|
PORT_TYPE SystemDefaultPortType = 0;
|
|
|
|
IP_PORT *pFreeInternetPorts = 0;
|
|
IP_PORT *pFreeIntranetPorts = 0;
|
|
|
|
PORT_RANGE *InternetPorts = 0;
|
|
PORT_RANGE *IntranetPorts = 0;
|
|
|
|
|
|
|
|
//
|
|
// Port management APIs
|
|
//
|
|
|
|
|
|
RPC_STATUS
|
|
InitializeIpPortManager(
|
|
void
|
|
)
|
|
{
|
|
HKEY hkey;
|
|
RPC_STATUS status;
|
|
DWORD size, type, value;
|
|
RPC_CHAR *pstr;
|
|
PORT_RANGE *pSet;
|
|
PORT_RANGE *pLast;
|
|
PORT_RANGE *pCurrent;
|
|
PORT_RANGE *pComplement;
|
|
PORT_RANGE *pNew;
|
|
|
|
LONG min, max;
|
|
|
|
|
|
InitializeCriticalSectionAndSpinCount(&PortLock, PREALLOCATE_EVENT_MASK);
|
|
|
|
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
PortConfigKey,
|
|
0,
|
|
KEY_READ,
|
|
&hkey);
|
|
|
|
if (status != RPC_S_OK)
|
|
{
|
|
if (status != ERROR_FILE_NOT_FOUND)
|
|
{
|
|
#if DBG
|
|
PrintToDebugger("RPCSS: Unable to open port config key: %d\n", status);
|
|
#endif
|
|
}
|
|
ASSERT(status == ERROR_FILE_NOT_FOUND);
|
|
|
|
fValidConfiguration = TRUE;
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
size = sizeof(value);
|
|
status = RegQueryValueEx(hkey,
|
|
DefaultPortType,
|
|
0,
|
|
&type,
|
|
(PBYTE)&value,
|
|
&size);
|
|
|
|
if ( status != RPC_S_OK
|
|
|| type != REG_SZ
|
|
|| ( *(RPC_CHAR *)&value != 'Y'
|
|
&& *(RPC_CHAR *)&value != 'y'
|
|
&& *(RPC_CHAR *)&value != 'N'
|
|
&& *(RPC_CHAR *)&value != 'n') )
|
|
{
|
|
RegCloseKey(hkey);
|
|
ASSERT(fValidConfiguration == FALSE);
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
if ( *(RPC_CHAR *)&value == 'Y'
|
|
|| *(RPC_CHAR *)&value == 'y')
|
|
{
|
|
SystemDefaultPortType = PORT_INTERNET;
|
|
}
|
|
else
|
|
{
|
|
SystemDefaultPortType = PORT_INTRANET;
|
|
}
|
|
|
|
size = sizeof(value);
|
|
status = RegQueryValueEx(hkey,
|
|
ExplictPortType,
|
|
0,
|
|
&type,
|
|
(PBYTE)&value,
|
|
&size);
|
|
|
|
if ( status != RPC_S_OK
|
|
|| type != REG_SZ
|
|
|| ( *(RPC_CHAR *)&value != 'Y'
|
|
&& *(RPC_CHAR *)&value != 'y'
|
|
&& *(RPC_CHAR *)&value != 'N'
|
|
&& *(RPC_CHAR *)&value != 'n') )
|
|
{
|
|
RegCloseKey(hkey);
|
|
ASSERT(fValidConfiguration == FALSE);
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
if ( *(RPC_CHAR *)&value == 'Y'
|
|
|| *(RPC_CHAR *)&value == 'y')
|
|
{
|
|
value = PORT_INTERNET;
|
|
}
|
|
else
|
|
{
|
|
value = PORT_INTRANET;
|
|
}
|
|
|
|
size = DEBUG_MIN(1, 100);
|
|
|
|
do
|
|
{
|
|
ASSERT(size);
|
|
pstr = alloca(size);
|
|
ASSERT(pstr);
|
|
|
|
status = RegQueryValueEx(hkey,
|
|
PortRanges,
|
|
0,
|
|
&type,
|
|
(PBYTE)pstr,
|
|
&size);
|
|
}
|
|
while (status == ERROR_MORE_DATA);
|
|
|
|
RegCloseKey(hkey);
|
|
|
|
if ( status != RPC_S_OK
|
|
|| type != REG_MULTI_SZ)
|
|
{
|
|
ASSERT(fValidConfiguration == FALSE);
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
//
|
|
// The user is going to specify a range of ports in the registery
|
|
// with a flag indicating if these ports are internet or intranet.
|
|
//
|
|
// ie, 500-550
|
|
// 560
|
|
// 559
|
|
// 2000-2048
|
|
// 2029-2049
|
|
//
|
|
// Note that order (in the REG_MULTI_SZ) and overlapping sets
|
|
// are ok. We must handle creating a port range list for this
|
|
// array and for the complement BUT NOT INCLUDING <=1024 by default.
|
|
//
|
|
// completment set to above is:
|
|
//
|
|
// 1025-1999
|
|
// 2050-32767
|
|
//
|
|
|
|
#define MIN_PORT 1025 // Only important for complement sets.
|
|
#define MAX_PORT 65535
|
|
|
|
pSet = 0;
|
|
pLast = 0;
|
|
|
|
while(*pstr)
|
|
{
|
|
RPC_CHAR *t;
|
|
|
|
#ifdef UNICODE
|
|
min = wcstol(pstr, &t, 10);
|
|
#else
|
|
min = strtol(pstr, &t, 10);
|
|
#endif
|
|
|
|
if (min > MAX_PORT || min < 0)
|
|
{
|
|
status = RPC_S_INVALID_ARG;
|
|
break;
|
|
}
|
|
|
|
if ( *t != 0
|
|
#ifdef UNICODE
|
|
&& *t != L'-')
|
|
#else
|
|
&& *t != '-')
|
|
#endif
|
|
{
|
|
status = RPC_S_INVALID_ARG;
|
|
break;
|
|
}
|
|
|
|
if (*t == 0)
|
|
{
|
|
max = min;
|
|
}
|
|
else
|
|
{
|
|
#ifdef UNICODE
|
|
max = wcstol(t + 1, &t, 10);
|
|
#else
|
|
min = strtol(t + 1, &t, 10);
|
|
#endif
|
|
|
|
if (max > MAX_PORT || max < 0 || max < min)
|
|
{
|
|
status = RPC_S_INVALID_ARG;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ASSERT(min <= max);
|
|
|
|
// Ok, got some ports, allocate a structure for them..
|
|
|
|
pNew = MIDL_user_allocate(sizeof(PORT_RANGE));
|
|
if (0 == pNew)
|
|
{
|
|
status = RPC_S_OUT_OF_MEMORY;
|
|
break;
|
|
}
|
|
|
|
pNew->pNext = 0;
|
|
|
|
pNew->Min = (unsigned short) min;
|
|
pNew->Max = (unsigned short) max;
|
|
|
|
// We can to maintain the set of ranges in order. As we insert
|
|
// we'll fix any ranges which overlap.
|
|
|
|
pCurrent = pSet;
|
|
pLast = 0;
|
|
|
|
for (;;)
|
|
{
|
|
if (0 == pSet)
|
|
{
|
|
pSet = pNew;
|
|
break;
|
|
}
|
|
|
|
if ( pNew->Min <= (pCurrent->Max + 1)
|
|
&& pNew->Max >= (pCurrent->Min - 1) )
|
|
{
|
|
// The ranges overlap or touch. We'll merge them now..
|
|
|
|
pCurrent->Min = MIN(pNew->Min, pCurrent->Min);
|
|
pCurrent->Max = MAX(pCurrent->Max, pNew->Max);
|
|
|
|
MIDL_user_free(pNew);
|
|
|
|
// Since the new larger range may overlap another existing
|
|
// range we just insert the larger range as if it was new...
|
|
pNew = pCurrent;
|
|
|
|
// Take current out of the list.
|
|
if (pLast)
|
|
{
|
|
pLast->pNext = pCurrent->pNext;
|
|
}
|
|
|
|
if (pSet == pNew)
|
|
{
|
|
pSet = pSet->pNext;
|
|
}
|
|
|
|
// Restart
|
|
pCurrent = pSet;
|
|
pLast = 0;
|
|
continue;
|
|
}
|
|
|
|
if (pNew->Min < pCurrent->Min)
|
|
{
|
|
// Found the spot
|
|
if (pLast)
|
|
{
|
|
pLast->pNext = pNew;
|
|
pNew->pNext = pCurrent;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(pCurrent == pSet);
|
|
pNew->pNext = pCurrent;
|
|
pSet = pNew;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
// Continue the search
|
|
pLast = pCurrent;
|
|
pCurrent = pCurrent->pNext;
|
|
|
|
if (0 == pCurrent)
|
|
{
|
|
// Reached the end of the list, insert it here.
|
|
pLast->pNext = pNew;
|
|
ASSERT(pNew->pNext == 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
ASSERT(pSet);
|
|
|
|
// Advance to the next string of the final null.
|
|
pstr = RpcpCharacter(pstr, 0) + 1;
|
|
}
|
|
|
|
if (pSet == 0)
|
|
{
|
|
status = RPC_S_INVALID_ARG;
|
|
}
|
|
|
|
if (value == PORT_INTERNET)
|
|
{
|
|
InternetPorts = pSet;
|
|
}
|
|
else
|
|
{
|
|
IntranetPorts = pSet;
|
|
}
|
|
|
|
if (status == RPC_S_OK)
|
|
{
|
|
// We've constructed the set of ports in the registry,
|
|
// now we need to compute the complement set.
|
|
|
|
pComplement = 0;
|
|
pCurrent = 0;
|
|
min = MIN_PORT;
|
|
|
|
while(pSet)
|
|
{
|
|
if (min < pSet->Min)
|
|
{
|
|
max = pSet->Min - 1;
|
|
ASSERT(max >= min);
|
|
|
|
pNew = MIDL_user_allocate(sizeof(PORT_RANGE));
|
|
if (0 == pNew)
|
|
{
|
|
status = RPC_S_OUT_OF_MEMORY;
|
|
break;
|
|
}
|
|
|
|
pNew->pNext = 0;
|
|
pNew->Min = (unsigned short) min;
|
|
pNew->Max = (unsigned short) max;
|
|
|
|
if (pComplement == 0)
|
|
{
|
|
pComplement = pCurrent = pNew;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(pCurrent);
|
|
pCurrent->pNext = pNew;
|
|
pCurrent = pNew;
|
|
}
|
|
}
|
|
|
|
min = MAX(MIN_PORT, pSet->Max + 1);
|
|
|
|
pSet = pSet->pNext;
|
|
}
|
|
|
|
if (status == RPC_S_OK && min < MAX_PORT)
|
|
{
|
|
// Final port in orginal set less then max, allocate final
|
|
// range for the set complement.
|
|
pNew = MIDL_user_allocate(sizeof(PORT_RANGE));
|
|
if (0 != pNew)
|
|
{
|
|
pNew->Min = (unsigned short) min;
|
|
pNew->Max = MAX_PORT;
|
|
pNew->pNext = 0;
|
|
if (pCurrent)
|
|
{
|
|
pCurrent->pNext = pNew;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(min == MIN_PORT);
|
|
pComplement = pNew;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
status = RPC_S_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
|
|
// Even if we failed assign the pointer, it's either
|
|
// null or needs to be freed.
|
|
|
|
if (value == PORT_INTERNET)
|
|
{
|
|
ASSERT(IntranetPorts == 0);
|
|
IntranetPorts = pComplement;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(InternetPorts == 0);
|
|
InternetPorts = pComplement;
|
|
}
|
|
}
|
|
|
|
if (status != RPC_S_OK)
|
|
{
|
|
ASSERT(fValidConfiguration == FALSE);
|
|
while(InternetPorts)
|
|
{
|
|
PORT_RANGE *pT = InternetPorts;
|
|
InternetPorts = InternetPorts->pNext;
|
|
MIDL_user_free(pT);
|
|
}
|
|
|
|
while(IntranetPorts)
|
|
{
|
|
PORT_RANGE *pT = IntranetPorts;
|
|
IntranetPorts = IntranetPorts->pNext;
|
|
MIDL_user_free(pT);
|
|
}
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
fValidConfiguration = TRUE;
|
|
fPortRestrictions = TRUE;
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
AllocatePort(
|
|
OUT IP_PORT **ppPort,
|
|
IN OUT IP_PORT **ppPortFreeList,
|
|
IN PORT_RANGE *pPortList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocates a port object for a specific process. It first tries
|
|
to use any ports in the free list. If there's nothing in the
|
|
port this then it tries to find a free port in the PortList
|
|
which is one of the sets computed during startup.
|
|
|
|
Arguments:
|
|
|
|
ppPort - Will contain the allocated port object if successful.
|
|
|
|
ppPortFreeList - Pointer to the head of the free list associated
|
|
with this type of port. Maybe modified during this call.
|
|
|
|
pPortList - Port ranges associated with this type of port.
|
|
|
|
Return Value:
|
|
|
|
TRUE - Port allocated
|
|
FALSE - Port not allocated
|
|
|
|
--*/
|
|
{
|
|
IP_PORT *pPort = 0;
|
|
|
|
// First see if there is free port to reuse.
|
|
|
|
if (*ppPortFreeList)
|
|
{
|
|
EnterCriticalSection(&PortLock);
|
|
if (*ppPortFreeList)
|
|
{
|
|
pPort = *ppPortFreeList;
|
|
*ppPortFreeList = pPort->pNext;
|
|
pPort->pNext = 0;
|
|
}
|
|
LeaveCriticalSection(&PortLock);
|
|
}
|
|
|
|
if (pPort == 0)
|
|
{
|
|
// No port in the free list, try to allocate one
|
|
// Assume we'll find a free port..
|
|
|
|
pPort = MIDL_user_allocate(sizeof(IP_PORT));
|
|
|
|
if (0 != pPort)
|
|
{
|
|
pPort->pNext = 0;
|
|
|
|
EnterCriticalSection(&PortLock);
|
|
|
|
while ( pPortList
|
|
&& pPortList->Min > pPortList->Max)
|
|
{
|
|
pPortList = pPortList->pNext;
|
|
}
|
|
|
|
if (pPortList)
|
|
{
|
|
ASSERT(pPortList->Min <= pPortList->Max);
|
|
|
|
pPort->Port = pPortList->Min;
|
|
pPortList->Min++;
|
|
|
|
// We could remove empty ranges from the list.
|
|
}
|
|
|
|
LeaveCriticalSection(&PortLock);
|
|
|
|
if (0 == pPortList)
|
|
{
|
|
MIDL_user_free(pPort);
|
|
pPort = 0;
|
|
#ifdef DEBUGRPC
|
|
DbgPrint("RPC: Out of reserved ports\n");
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
// REVIEW: Post SUR we should look at adding events for
|
|
// allocation and failure to allocate IP ports
|
|
|
|
*ppPort = pPort;
|
|
|
|
return(pPort != 0);
|
|
}
|
|
|
|
|
|
|
|
|
|
error_status_t
|
|
AllocateReservedIPPort(
|
|
IN HPROCESS hProcess,
|
|
IN PORT_TYPE PortType,
|
|
OUT long *pAllocationStatus,
|
|
OUT unsigned short *pAllocatedPort
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Remote manager for RPC runtime to call locally to allocate
|
|
a local port. The call and process parameters must be valid
|
|
and called only locally. Based on the PortType paramet a
|
|
IP port maybe allocated for the calling process. The
|
|
allocationstatus contains the result of the port allocation
|
|
step.
|
|
|
|
Arguments:
|
|
|
|
hProcess - Valid process context handle allocated with
|
|
a call to OpenEndpointMapper.
|
|
PortType - One of
|
|
PORT_INTERNET
|
|
PORT_INTRANET
|
|
PORT_DEFAULT
|
|
Used to determine which port range to allocate from.
|
|
pAllocationStatus -
|
|
RPC_S_OK - successfully allocated a port.
|
|
RPC_S_OUT_OF_RESOURES - no ports available.
|
|
pAllocatePort - If allocation status is RPC_S_OK then
|
|
this contains the value of the port allocated.
|
|
If zero it means that there are no port restrictions
|
|
and any port maybe used.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK
|
|
RPC_S_INVALID_ARG - configuration error or PortType out of range.
|
|
RPC_S_ACCESS_ DENIED - not called locally.
|
|
|
|
--*/
|
|
{
|
|
PROCESS *pProcess = (PROCESS *)hProcess;
|
|
IP_PORT *pPort;
|
|
UINT type;
|
|
BOOL b;
|
|
|
|
*pAllocatedPort = 0;
|
|
*pAllocationStatus = RPC_S_OK;
|
|
|
|
ASSERT(pProcess);
|
|
|
|
if (!fValidConfiguration)
|
|
{
|
|
return(RPC_S_INVALID_ARG);
|
|
}
|
|
|
|
if ( (I_RpcBindingInqTransportType(0, &type) != RPC_S_OK)
|
|
|| (type != TRANSPORT_TYPE_LPC)
|
|
|| (0 == pProcess)
|
|
|| (pProcess->MagicVal != PROCESS_MAGIC_VALUE ) )
|
|
{
|
|
return(RPC_S_ACCESS_DENIED);
|
|
}
|
|
|
|
if (PortType > PORT_DEFAULT || PortType < PORT_INTERNET)
|
|
{
|
|
return(RPC_S_INVALID_ARG);
|
|
}
|
|
|
|
if (fPortRestrictions == FALSE)
|
|
{
|
|
// No port restrictions on this machine, just use zero.
|
|
// This is the common case.
|
|
ASSERT(*pAllocatedPort == 0);
|
|
ASSERT(*pAllocationStatus == 0);
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
// Need to actually allocate a unique port for this process.
|
|
|
|
if (PortType == PORT_DEFAULT)
|
|
{
|
|
// Allocate using default policy
|
|
PortType = SystemDefaultPortType;
|
|
}
|
|
|
|
ASSERT(PortType == PORT_INTERNET || PortType == PORT_INTRANET);
|
|
|
|
|
|
pPort = 0;
|
|
|
|
if (PortType == PORT_INTERNET)
|
|
{
|
|
b = AllocatePort(&pPort,
|
|
&pFreeInternetPorts,
|
|
InternetPorts
|
|
);
|
|
}
|
|
else
|
|
{
|
|
b = AllocatePort(&pPort,
|
|
&pFreeIntranetPorts,
|
|
IntranetPorts);
|
|
}
|
|
|
|
if (!b)
|
|
{
|
|
ASSERT(pPort == 0);
|
|
// REVIEW: Do we want a unique error code if no ports
|
|
// are available?
|
|
*pAllocationStatus = RPC_S_OUT_OF_RESOURCES;
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
ASSERT(pPort);
|
|
ASSERT(pPort->pNext == 0);
|
|
|
|
pPort->Type = (unsigned short) PortType;
|
|
|
|
pPort->pNext = pProcess->pPorts;
|
|
pProcess->pPorts = pPort;
|
|
|
|
*pAllocatedPort = pPort->Port;
|
|
|
|
ASSERT(*pAllocationStatus == RPC_S_OK);
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
HPROCESS_rundown(
|
|
HPROCESS hProcess
|
|
)
|
|
{
|
|
PROCESS *pProcess = (PROCESS *)hProcess;
|
|
IP_PORT *pCurrent;
|
|
IP_PORT *pSave;
|
|
|
|
ASSERT(pProcess);
|
|
ASSERT(pProcess->MagicVal == PROCESS_MAGIC_VALUE);
|
|
|
|
pCurrent = pProcess->pPorts;
|
|
if (pCurrent)
|
|
{
|
|
EnterCriticalSection(&PortLock);
|
|
|
|
do
|
|
{
|
|
pSave = pCurrent->pNext;
|
|
|
|
if (pCurrent->Type == PORT_INTERNET)
|
|
{
|
|
pCurrent->pNext = pFreeInternetPorts;
|
|
pFreeInternetPorts = pCurrent;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(pCurrent->Type == PORT_INTRANET);
|
|
pCurrent->pNext = pFreeIntranetPorts;
|
|
pFreeIntranetPorts = pCurrent;
|
|
}
|
|
|
|
pCurrent = pSave;
|
|
}
|
|
while(pCurrent);
|
|
|
|
LeaveCriticalSection(&PortLock);
|
|
}
|
|
|
|
MIDL_user_free(pProcess);
|
|
|
|
return;
|
|
}
|