Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1946 lines
64 KiB

/****************************************************************************/
// tsrvcom.c
//
// RDPWSX routines for lower-layer (GCC, RDPWD) communications support
//
// Copyright (C) 1991-2000 Microsoft Corporation
/****************************************************************************/
#include <TSrv.h>
#include <TSrvCom.h>
#include <TSrvInfo.h>
#include <_TSrvInfo.h>
#include <_TSrvCom.h>
#include <TSrvSec.h>
#include <licecert.h>
// Data declarations
ULONG g_GCCAppID = 0;
BOOL g_fGCCRegistered = FALSE;
//*************************************************************
//
// TSrvValidateServerCertificate()
//
// Purpose: Validate the certificate received from the shadow
// client's server is legit. Note that this function
// is very similar to certificate validation by the
// client.
//
// Return: STATUS_SUCCESS - Success
// other - Failure
//
// History: 4/26/99 jparsons Created
//
//*************************************************************
NTSTATUS
TSrvValidateServerCertificate(HANDLE hStack,
CERT_TYPE *pCertType,
PULONG pcbServerPubKey,
PBYTE *ppbServerPubKey,
ULONG cbShadowRandom,
PBYTE pShadowRandom,
LONG ulTimeout)
{
ULONG ulCertVersion;
NTSTATUS status;
PSHADOWCERT pShadowCert = NULL;
PBYTE pbNetCert;
PBYTE pbNetRandom;
ULONG ulBytesReturned;
SECURITYTIMEOUT securityTimeout;
*pcbServerPubKey = 0;
*ppbServerPubKey = NULL;
*pCertType = CERT_TYPE_INVALID;
securityTimeout.ulTimeout = ulTimeout;
// Wait for the shadow server certificate to arrive and determine how
// much memory to allocate. Note that one potential outcome is that the
// other server is not encrypting and thus sends no certificate
TRACE((DEBUG_TSHRSRV_NORMAL,
"TShrSRV: Waiting to receive server certificate: msec=%ld\n", ulTimeout));
status = IcaStackIoControl(hStack,
IOCTL_TSHARE_GET_CERT_DATA,
&securityTimeout, sizeof(securityTimeout),
NULL,
0,
&ulBytesReturned);
if (status == STATUS_BUFFER_TOO_SMALL) {
ULONG ulBytesNeeded = ulBytesReturned;
TRACE((DEBUG_TSHRSRV_NORMAL,
"TShrSRV: Need %ld bytes for certificate\n", ulBytesNeeded));
pShadowCert = TSHeapAlloc(0, ulBytesNeeded, TS_HTAG_TSS_CERTIFICATE);
if (pShadowCert != NULL) {
memset(pShadowCert, 0, sizeof(PSHADOWCERT));
pShadowCert->encryptionMethod = 0xffffffff;
status = IcaStackIoControl(hStack,
IOCTL_TSHARE_GET_CERT_DATA,
&securityTimeout, sizeof(securityTimeout),
pShadowCert,
ulBytesNeeded,
&ulBytesReturned);
// calculate pointers to embedded data (if any)
if (status == STATUS_SUCCESS) {
TRACE((DEBUG_TSHRSRV_ERROR, "TShrSRV: Received random [%ld], Certificate [%ld]\n",
pShadowCert->shadowRandomLen, pShadowCert->shadowCertLen));
if (pShadowCert->encryptionLevel != 0) {
pbNetRandom = pShadowCert->data;
pbNetCert = pbNetRandom + pShadowCert->shadowRandomLen;
// Save off the server random to establish session keys later
if (pShadowCert->shadowRandomLen == RANDOM_KEY_LENGTH) {
memcpy(pShadowRandom, pbNetRandom, pShadowCert->shadowRandomLen);
}
else {
memset(pShadowRandom, 0, RANDOM_KEY_LENGTH);
TRACE((DEBUG_TSHRSRV_ERROR,
"TShrSRV: Invalid shadow random key length: %ld\n",
pShadowCert->shadowRandomLen));
status = STATUS_INVALID_PARAMETER;
}
}
// else there is no encryption so we're done!
else {
TRACE((DEBUG_TSHRSRV_NORMAL, "TShrSRV: Encryption is disabled\n"));
return STATUS_SUCCESS;
}
}
else {
TRACE((DEBUG_TSHRSRV_ERROR,
"TShrSRV: IOCTL_TSHARE_GET_CERT_DATA failed: rc=%lx\n",
status));
}
}
else {
TRACE((DEBUG_TSHRSRV_ERROR,
"TShrSRV: Could not allocate memory to validate shadow certificate\n"))
status = STATUS_NO_MEMORY;
}
}
// The other server returned a certificate, so validate it
if (status == STATUS_SUCCESS && pShadowCert != NULL) {
ULONG cbNetCert = pShadowCert->shadowCertLen;
memcpy(&ulCertVersion, pbNetCert, sizeof(ULONG));
// assume certificate validation is going to fail ;-(
status = STATUS_LICENSE_VIOLATION;
//
// decode and validate proprietory certificate.
//
if( CERT_CHAIN_VERSION_2 > GET_CERTIFICATE_VERSION(ulCertVersion)) {
Hydra_Server_Cert serverCertificate;
*pCertType = CERT_TYPE_PROPRIETORY;
// Unpack and validate the legacy certificate
if (UnpackServerCert(pbNetCert, cbNetCert, &serverCertificate)) {
if (ValidateServerCert(&serverCertificate)) {
*ppbServerPubKey = TSHeapAlloc(
HEAP_ZERO_MEMORY,
serverCertificate.PublicKeyData.wBlobLen,
TS_HTAG_TSS_PUBKEY);
// Copy the public key from inside the proprietary blob!
if (*ppbServerPubKey != NULL) {
memcpy(*ppbServerPubKey,
serverCertificate.PublicKeyData.pBlob,
serverCertificate.PublicKeyData.wBlobLen);
*pcbServerPubKey = serverCertificate.PublicKeyData.wBlobLen;
status = STATUS_SUCCESS;
}
else {
status = STATUS_NO_MEMORY;
TRACE((DEBUG_TSHRSRV_ERROR,
"TShrSRV: Failed to allocate %u bytes for server public key\n",
*pcbServerPubKey)) ;
}
}
else {
TRACE((DEBUG_TSHRSRV_ERROR,
"TShrSRV: Invalid proprietary server certificate received\n"));
}
}
else {
TRACE((DEBUG_TSHRSRV_ERROR,
"TShrSRV: Failed to unpack proprietary server certificate\n")) ;
}
}
//
// decode X509 certificate and extract public key
//
else if( MAX_CERT_CHAIN_VERSION >= GET_CERTIFICATE_VERSION(ulCertVersion)) {
ULONG fDates = CERT_DATE_DONT_VALIDATE;
LICENSE_STATUS licStatus;
*pCertType = CERT_TYPE_X509;
*ppbServerPubKey = NULL;
// Determine the length of the public key. Note that this stinking
// function is not multi-thread safe!
TRACE((DEBUG_TSHRSRV_ERROR,
"TShrSRV: X.509 server certificate length: %ld\n",
cbNetCert)) ;
// Watch out! X509 routines are not thread safe.
EnterCriticalSection( &g_TSrvCritSect );
licStatus = VerifyCertChain(pbNetCert, cbNetCert, NULL,
pcbServerPubKey, &fDates);
LeaveCriticalSection( &g_TSrvCritSect );
if( LICENSE_STATUS_INSUFFICIENT_BUFFER == licStatus )
{
*ppbServerPubKey = TSHeapAlloc(HEAP_ZERO_MEMORY, *pcbServerPubKey,
TS_HTAG_TSS_PUBKEY);
if (*ppbServerPubKey != NULL) {
EnterCriticalSection( &g_TSrvCritSect );
licStatus = VerifyCertChain(pbNetCert, cbNetCert,
*ppbServerPubKey, pcbServerPubKey,
&fDates);
LeaveCriticalSection( &g_TSrvCritSect );
if (LICENSE_STATUS_OK == licStatus) {
status = STATUS_SUCCESS;
}
else {
TRACE((DEBUG_TSHRSRV_ERROR,
"TShrSRV: Failed to verify X.509 server certificate: %ld\n",
licStatus)) ;
// torch the server public key memory
TSHeapFree(*ppbServerPubKey);
*ppbServerPubKey = NULL;
}
}
else {
status = STATUS_NO_MEMORY;
TRACE((DEBUG_TSHRSRV_ERROR,
"TShrSRV: Failed to allocate %u bytes for server public key\n",
*pcbServerPubKey)) ;
}
}
else {
TRACE((DEBUG_TSHRSRV_ERROR,
"TShrSRV: Could not decode X.509 server public key length: %d\n",
licStatus )) ;
}
}
//
// don't know how to decode this version of certificate
//
else {
status = LICENSE_STATUS_UNSUPPORTED_VERSION;
TRACE((DEBUG_TSHRSRV_ERROR,"TShrSRV: Invalid certificate version: %ld\n",
GET_CERTIFICATE_VERSION(ulCertVersion))) ;
}
}
// Something messed up!
else {
// Treat a timeout as fatal.
if (status == STATUS_TIMEOUT)
status = STATUS_IO_TIMEOUT;
TRACE((DEBUG_TSHRSRV_ERROR,
"TShrSRV: Failed to retrieve shadow server cerfificate, rc=%lx, "
"pShadowCert=%p\n", status, pShadowCert));
}
if (pShadowCert != NULL)
TSHeapFree(pShadowCert);
return status;
}
//*************************************************************
//
// TSrvCalculateUserDataSize()
//
// Purpose: Calculates the amount of user data passed in
// the pCreateMessage message
//
// Parameters: IN [pCreateMessage] - GCC CreateIndicationMessage
//
// Return: User data size (bytes)
//
// Notes: Function trucks it's way through the GCC user_data_list
// structure summing up the amount of user data supplied
//
// History: 07-17-97 BrianTa Created
//
//*************************************************************
ULONG
TSrvCalculateUserDataSize(IN CreateIndicationMessage *pCreateMessage)
{
int i;
ULONG ulUserDataSize;
GCCUserData *pClientUserData;
TRACE((DEBUG_TSHRSRV_FLOW,
"TShrSRV: TSrvCalculateUserDataSize entry\n"));
ulUserDataSize = 0;
TSrvDumpUserData(pCreateMessage);
for (i=0; i<pCreateMessage->number_of_user_data_members; i++)
{
pClientUserData = pCreateMessage->user_data_list[i];
if (pClientUserData != NULL)
{
// Calcu KEY size
if (pClientUserData->key.key_type == GCC_OBJECT_KEY)
{
ulUserDataSize += (sizeof(ULONG) *
pClientUserData->key.u.object_id.long_string_length);
}
else
{
ulUserDataSize += (sizeof(UCHAR) *
pClientUserData->key.u.h221_non_standard_id.octet_string_length);
}
// Calc client size
if (pClientUserData->octet_string)
{
// Allow for the extra indirection
ulUserDataSize += sizeof(*(pClientUserData->octet_string));
// Allow for the actual data
ulUserDataSize += (sizeof(UCHAR) *
pClientUserData->octet_string->octet_string_length);
}
}
}
TRACE((DEBUG_TSHRSRV_FLOW,
"TShrSRV: TSrvCalculateUserDataSize exit - 0x%x\n", ulUserDataSize));
return (ulUserDataSize);
}
//*************************************************************
//
// TSrvSaveUserDataMember()
//
// Purpose: Saves off the provided userData member
//
// Parameters: IN [pInUserData] - Source userData
// OUT [pOutUserData] - Destination userData
// IN OUT [pulUserDataOffset] - Re-base offset
//
// Return: void
//
// Notes: This routine copies the src user data into the
// destination user data, re-basing all the dest
// user data ptrs to the provided pulUserDataOffset
//
// History: 07-17-97 BrianTa Created
//
//*************************************************************
void
TSrvSaveUserDataMember(IN GCCUserData *pInUserData,
OUT GCCUserData *pOutUserData,
IN PUSERDATAINFO pUserDataInfo,
IN OUT PULONG pulUserDataOffset)
{
ULONG ulUserDataSize;
GCCOctetString UNALIGNED *pOctetString;
TRACE((DEBUG_TSHRSRV_FLOW,
"TShrSRV: TSrvSaveUserDataMember entry\n"));
*pOutUserData = *pInUserData;
// Key data and length
if (pInUserData->key.key_type == GCC_OBJECT_KEY)
{
pOutUserData->key.u.object_id.long_string =
(PULONG FAR)ULongToPtr((*pulUserDataOffset));
ulUserDataSize =
pOutUserData->key.u.object_id.long_string_length * sizeof(ULONG);
memcpy((PCHAR) pUserDataInfo + *pulUserDataOffset,
pInUserData->key.u.object_id.long_string,
ulUserDataSize);
}
else
{
pOutUserData->key.u.h221_non_standard_id.octet_string =
(PUCHAR FAR)ULongToPtr((*pulUserDataOffset));
ulUserDataSize =
pInUserData->key.u.h221_non_standard_id.octet_string_length * sizeof(UCHAR);
memcpy((PCHAR) pUserDataInfo + *pulUserDataOffset,
pInUserData->key.u.h221_non_standard_id.octet_string,
ulUserDataSize);
}
*pulUserDataOffset += ulUserDataSize;
// Client data ptr, length, and data
if (pInUserData->octet_string &&
pInUserData->octet_string->octet_string)
{
// Data ptr
pOutUserData->octet_string = (GCCOctetString *)ULongToPtr((*pulUserDataOffset));
pOctetString = (GCCOctetString *)
((PUCHAR) pOutUserData->octet_string +
(ULONG_PTR)pUserDataInfo);
*pulUserDataOffset += sizeof(*(pInUserData->octet_string));
// Data length
pOctetString->octet_string_length =
pInUserData->octet_string->octet_string_length;
pOctetString->octet_string = (unsigned char FAR *)ULongToPtr((*pulUserDataOffset));
ulUserDataSize =
pInUserData->octet_string->octet_string_length * sizeof(UCHAR);
// Data
memcpy((PCHAR) pUserDataInfo + *pulUserDataOffset,
pInUserData->octet_string->octet_string,
ulUserDataSize);
*pulUserDataOffset += ulUserDataSize;
}
TRACE((DEBUG_TSHRSRV_FLOW,
"TShrSRV: TSrvSaveUserDataMember exit\n"));
}
//*************************************************************
//
// TSrvSaveUserData()
//
// Purpose: Saves off the provided userData
//
// Parameters: IN [pTSrvInfo] - TSrvInfo object
// IN [pCreateMessage] - CreateIndicationMessage
//
// Return: STATUS_SUCCESS - Success
// STATUS_NO_MEMORY - Failure
//
// Notes: This routine makes a new copy of the userdata
// provided by the GCC CreateIndicationMessage
//
// History: 07-17-97 BrianTa Created
//
//*************************************************************
NTSTATUS
TSrvSaveUserData(IN PTSRVINFO pTSrvInfo,
IN CreateIndicationMessage *pCreateMessage)
{
DWORD i;
ULONG ulUserDataInfoSize;
ULONG ulUserDataOffset;
ULONG ulUserDataSize;
PUSERDATAINFO pUserDataInfo;
NTSTATUS ntStatus;
TRACE((DEBUG_TSHRSRV_FLOW,
"TShrSRV: TSrvSaveUserData entry\n"));
ntStatus = STATUS_NO_MEMORY;
// Calculate the size of the USERDATAINFO control structure and the
// size of the data buffer needed to hold the GCC UserData
ulUserDataInfoSize = sizeof(USERDATAINFO) +
sizeof(GCCUserData) * pCreateMessage->number_of_user_data_members;
ulUserDataSize = TSrvCalculateUserDataSize(pCreateMessage);
pUserDataInfo = TSHeapAlloc(HEAP_ZERO_MEMORY,
ulUserDataInfoSize + ulUserDataSize,
TS_HTAG_TSS_USERDATA_IN);
TS_ASSERT(pTSrvInfo->pUserDataInfo == NULL);
pTSrvInfo->pUserDataInfo = pUserDataInfo;
// If we can allocate enough memory to do the copy, then loop through
// each member saving the associated userdata
if (pUserDataInfo)
{
TRACE((DEBUG_TSHRSRV_DETAIL, "TShrSRV: Allocated 0x%x bytes for UserData save space\n",
ulUserDataInfoSize + ulUserDataSize));
pUserDataInfo->cbSize = ulUserDataInfoSize + ulUserDataSize;
pUserDataInfo->hDomain = pTSrvInfo->hDomain;
pUserDataInfo->ulUserDataMembers = pCreateMessage->number_of_user_data_members;
ulUserDataOffset = ulUserDataInfoSize;
TRACE((DEBUG_TSHRSRV_DETAIL, "TShrSRV: Saving each UserDataMenber to save space\n"));
for (i=0; i<pUserDataInfo->ulUserDataMembers; i++)
{
TSrvSaveUserDataMember(pCreateMessage->user_data_list[i],
&pUserDataInfo->rgUserData[i],
pUserDataInfo,
&ulUserDataOffset);
}
TS_ASSERT(ulUserDataOffset <= ulUserDataInfoSize + ulUserDataSize);
ntStatus = STATUS_SUCCESS;
}
else
{
TRACE((DEBUG_TSHRSRV_WARN, "TShrSRV: Can't allocate 0x%x for userData save space\n",
ulUserDataInfoSize + ulUserDataSize));
}
TRACE((DEBUG_TSHRSRV_FLOW,
"TShrSRV: TSrvSaveUserData exit - 0x%x\n", ntStatus));
return (ntStatus);
}
//*************************************************************
//
// TSrvSignalIndication()
//
// Purpose: Signals the worker thread
//
// Parameters: IN [pTSrvInfo] - TSrvInfo object
// IN [ntStatus] - Signaling status
//
// Return: void
//
// History: 07-17-97 BrianTa Created
//
//*************************************************************
void
TSrvSignalIndication(IN PTSRVINFO pTSrvInfo,
IN NTSTATUS ntStatus)
{
TRACE((DEBUG_TSHRSRV_FLOW,
"TShrSRV: TSrvSignalIndication entry\n"));
TS_ASSERT(pTSrvInfo->hWorkEvent);
TRACE((DEBUG_TSHRSRV_DEBUG, "TShrSRV: Signaling workEvent %p, status 0x%x\n",
pTSrvInfo->hWorkEvent, ntStatus));
pTSrvInfo->ntStatus = ntStatus;
if (!SetEvent(pTSrvInfo->hWorkEvent))
{
TRACE((DEBUG_TSHRSRV_DEBUG, "TShrSRV: Cannot Signal workEvent %p, gle 0x%x\n",
pTSrvInfo->hWorkEvent, GetLastError()));
ASSERT(0);
}
TRACE((DEBUG_TSHRSRV_FLOW,
"TShrSRV: TSrvSignalIndication exit\n"));
}
//*************************************************************
//
// TSrvHandleCreateInd()
//
// Purpose: Handles GCC Gcc_Create_Indication
//
// Parameters: IN [pCreateInd] - CreateIndicationMessage
//
// Return: void
//
// History: 07-17-97 BrianTa Created
//
//*************************************************************
void
TSrvHandleCreateInd(IN PTSRVINFO pTSrvInfo,
IN CreateIndicationMessage *pCreateInd)
{
NTSTATUS ntStatus;
TRACE((DEBUG_TSHRSRV_FLOW,
"TShrSRV: TSrvHandleCreateInd entry\n"));
// Reject the conference if we are not allowed to accept any new calls
if (TSrvIsReady(FALSE))
{
TRACE((DEBUG_TSHRSRV_NORMAL,
"TShrSRV: Accepting create indication - Domain %p\n",
pTSrvInfo->hDomain));
TSrvDumpCreateIndDetails(pCreateInd);
pTSrvInfo->hConnection = pCreateInd->connection_handle;
// Save off UserData
TRACE((DEBUG_TSHRSRV_DETAIL,
"TShrSRV: Attempting to save CreateInd userData\n"));
ntStatus = TSrvSaveUserData(pTSrvInfo, pCreateInd);
TRACE((DEBUG_TSHRSRV_DETAIL,
"TShrSRV: Save userData was%s successful\n",
(ntStatus == STATUS_SUCCESS ? "" : " not")));
}
else
{
TRACE((DEBUG_TSHRSRV_NORMAL,
"TShrSRV: Rejecting create indication - Domain %p\n",
pTSrvInfo->hDomain));
ntStatus = STATUS_DEVICE_NOT_READY;
}
// Signal completion, and pass along the completion status
TSrvSignalIndication(pTSrvInfo, ntStatus);
TRACE((DEBUG_TSHRSRV_FLOW,
"TShrSRV: TSrvHandleCreateInd exit\n"));
}
//*************************************************************
//
// TSrvHandleTerminateInd()
//
// Purpose: Handles GCC Gcc_Terminate_Ind
//
// Parameters: IN [pTermInd] - TerminateIndicationMessage
//
// Return: void
//
// History: 07-17-97 BrianTa Created
//
//*************************************************************
void
TSrvHandleTerminateInd(IN PTSRVINFO pTSrvInfo,
IN TerminateIndicationMessage *pTermInd)
{
BYTE fuConfState;
GCCError GCCrc;
TRACE((DEBUG_TSHRSRV_FLOW,
"TShrSRV: TSrvHandleTerminateInd entry\n"));
TRACE((DEBUG_TSHRSRV_DETAIL,
"TShrSRV: Domain %p\n", pTSrvInfo->hDomain));
TSrvDumpGCCReasonDetails(pTermInd->reason,
"GCCTerminateConfirm");
TSrvReferenceInfo(pTSrvInfo);
EnterCriticalSection(&pTSrvInfo->cs);
// If the disconnect was not requested (client, network) then disconnect the
// connection, flag the status, and wait for ICASRV to ping us via the normal
// termination mechanism.
if (!pTSrvInfo->fDisconnect)
{
fuConfState = pTSrvInfo->fuConfState;
pTSrvInfo->fDisconnect = TRUE;
pTSrvInfo->ulReason = GCC_REASON_USER_INITIATED;
pTSrvInfo->fuConfState = TSRV_CONF_TERMINATED;
GCCrc = GCCConferenceTerminateRequest(pTSrvInfo->hIca, NULL,
pTSrvInfo->hConnection, pTSrvInfo->ulReason);
TSrvDumpGCCRCDetails(GCCrc,
"GCCConferenceTerminateRequest");
pTSrvInfo->hConnection = NULL;
if (fuConfState == TSRV_CONF_PENDING)
TSrvSignalIndication(pTSrvInfo, STATUS_SUCCESS);
}
LeaveCriticalSection(&pTSrvInfo->cs);
TSrvDereferenceInfo(pTSrvInfo);
TRACE((DEBUG_TSHRSRV_FLOW,
"TShrSRV: TSrvHandleTerminateInd exit\n"));
}
//*************************************************************
//
// TSrvHandleDisconnectInd()
//
// Purpose: Handles GCC Gcc_Disconnect_Ind
//
// Parameters: IN [pDiscInd] - DisconnectIndicationMessage
//
// Return: void
//
// History: 07-17-97 BrianTa Created
//
//*************************************************************
void
TSrvHandleDisconnectInd(IN PTSRVINFO pTSrvInfo,
IN DisconnectIndicationMessage *pDiscInd)
{
TRACE((DEBUG_TSHRSRV_FLOW,
"TShrSRV: TSrvHandleDisconnectInd entry\n"));
TRACE((DEBUG_TSHRSRV_DETAIL,
"TShrSRV: Domain = 0x%x\n", pTSrvInfo->hDomain));
TRACE((DEBUG_TSHRSRV_FLOW,
"TShrSRV: TSrvHandleDisconnectInd exit\n"));
}
//*************************************************************
//
// TSrvGCCCallBack()
//
// Purpose: Handles GCC Callback messages
//
// Parameters: IN [pDiscInd] - DisconnectIndicationMessage
//
// Return: GCC_CALLBACK_PROCESSED
//
// History: 07-17-97 BrianTa Created
//
//*************************************************************
T120Boolean
APIENTRY
TSrvGCCCallBack(IN GCCMessage *pGCCMessage)
{
PTSRVINFO pTSrvInfo;
TRACE((DEBUG_TSHRSRV_FLOW,
"TShrSRV: TSrvGCCCallBack entry\n"));
TSrvDumpCallBackMessage(pGCCMessage);
pTSrvInfo = pGCCMessage->user_defined;
TSrvInfoValidate(pTSrvInfo);
if (pTSrvInfo)
{
switch (pGCCMessage->message_type)
{
case GCC_CREATE_INDICATION:
TSrvHandleCreateInd(pTSrvInfo, &(pGCCMessage->u.create_indication));
break;
case GCC_DISCONNECT_INDICATION:
TSrvHandleDisconnectInd(pTSrvInfo, &(pGCCMessage->u.disconnect_indication));
break;
case GCC_TERMINATE_INDICATION:
TSrvHandleTerminateInd(pTSrvInfo, &(pGCCMessage->u.terminate_indication));
break;
}
}
TRACE((DEBUG_TSHRSRV_FLOW,
"TShrSRV: TSrvGCCCallBack exit - GCC_CALLBACK_PROCESSED\n"));
return (GCC_CALLBACK_PROCESSED);
}
//*************************************************************
//
// TSrvRegisterNC()
//
// Purpose: Registers TShareSrv as Node Comtroller
//
// Parameters: void
//
// Return: TRUE - Success
// FALSE - Failure
//
// History: 07-17-97 BrianTa Created
//
//*************************************************************
BOOL
TSrvRegisterNC(void)
{
USHORT usCapMask;
USHORT usInitFlags;
GCCVersion gccVersion;
GCCVersion highVersion;
GCCVersion versionRequested;
GCCError GCCrc;
TRACE((DEBUG_TSHRSRV_FLOW,
"TShrSRV: TSrvRegisterNC entry\n"));
usInitFlags = 0xffff;
usCapMask = 0xffff;
versionRequested.major_version = 1;
versionRequested.minor_version = 0;
TRACE((DEBUG_TSHRSRV_NORMAL, "TShrSRV: Registering Node Controller\n"));
GCCrc = GCCRegisterNodeControllerApplication(TSrvGCCCallBack,
NULL,
versionRequested,
&usInitFlags,
&g_GCCAppID,
&usCapMask,
&highVersion,
&gccVersion);
g_fGCCRegistered = (GCCrc == GCC_NO_ERROR);
if (g_fGCCRegistered)
{
TRACE((DEBUG_TSHRSRV_DETAIL,
"TShrSRV: RegNC - usInitFlags 0x%x, AppID 0x%x, capMask 0x%x\n",
usInitFlags, g_GCCAppID, usCapMask));
TRACE((DEBUG_TSHRSRV_DETAIL,
"TShrSRV: RegNC - High Version (major %d, minor %d)\n",
highVersion.major_version,
highVersion.minor_version));
TRACE((DEBUG_TSHRSRV_DETAIL,
"TShrSRV: RegNC - Version (major %d, minor %d)\n",
gccVersion.major_version,
gccVersion.minor_version));
}
TRACE((DEBUG_TSHRSRV_FLOW,
"TShrSRV: TSrvRegisterNC exit - 0x%x\n", g_fGCCRegistered));
return (g_fGCCRegistered);
}
//*************************************************************
//
// TSrvUnregisterNC()
//
// Purpose: Unregisters TShareSrv as Node Controller
//
// Parameters: void
//
// Return: void
//
// History: 07-17-97 BrianTa Created
//
//*************************************************************
void
TSrvUnregisterNC(void)
{
GCCError GCCrc;
TRACE((DEBUG_TSHRSRV_FLOW, "TShrSRV: TSrvUnregisterNC entry\n"));
if (g_fGCCRegistered)
{
TRACE((DEBUG_TSHRSRV_NORMAL, "TShrSRV: Performing GCCCleanup\n"));
GCCrc = GCCCleanup(g_GCCAppID);
g_fGCCRegistered = FALSE;
TSrvDumpGCCRCDetails(GCCrc, "TShrSRV: GCCCleanup\n");
}
TRACE((DEBUG_TSHRSRV_FLOW, "TShrSRV: TSrvUnregisterNC exit\n"));
}
//*************************************************************
//
// TSrvBindStack()
//
// Purpose: Initiates MCSMux stack association
//
// Parameters: IN [pTSrvInfo] - TShareSrv object
//
// Return: void
//
// History: 07-17-97 BrianTa Created
//
//*************************************************************
NTSTATUS
TSrvBindStack(IN PTSRVINFO pTSrvInfo)
{
NTSTATUS ntStatus;
GCCError GCCrc;
TRACE((DEBUG_TSHRSRV_FLOW,
"TShrSRV: TSrvBindStack entry\n"));
TS_ASSERT(pTSrvInfo);
TS_ASSERT(pTSrvInfo->hStack);
TRACE((DEBUG_TSHRSRV_NORMAL, "TShrSRV: Binding Ica stack\n"));
GCCrc = GCCConferenceInit(pTSrvInfo->hIca,
pTSrvInfo->hStack,
pTSrvInfo,
&pTSrvInfo->hDomain);
if (GCCrc == GCC_NO_ERROR)
{
ntStatus = STATUS_SUCCESS;
TRACE((DEBUG_TSHRSRV_DEBUG, "TShrSRV: Ica stack bound successfully\n"));
}
else
{
ntStatus = STATUS_UNSUCCESSFUL;
pTSrvInfo->hDomain = NULL;
TRACE((DEBUG_TSHRSRV_ERROR,
"TShrSRV: Unable to bind stack - hStack %p, GCCrc 0x%x\n",
pTSrvInfo->hStack, GCCrc));
}
TRACE((DEBUG_TSHRSRV_FLOW,
"TShrSRV: TSrvBindStack exit - 0x%x\n", ntStatus));
return (ntStatus);
}
//*************************************************************
//
// TSrvInitWDConnectInfo()
//
// Purpose: Performs WDTshare connection initialization
//
// Return: STATUS_SUCCESS - Success
// other - Failure
//
// History: 07-17-97 BrianTa Created
//
//*************************************************************
NTSTATUS
TSrvInitWDConnectInfo(IN HANDLE hStack,
IN PTSRVINFO pTSrvInfo,
IN OUT PUSERDATAINFO *ppUserDataInfo,
IN ULONG ioctl,
IN PBYTE pModuleData,
IN ULONG cbModuleData,
IN BOOLEAN bGetCert,
OUT PVOID *ppSecInfo)
{
int i;
ULONG ulInBufferSize;
ULONG ulBytesReturned;
PUSERDATAINFO pUserDataInfo;
PUSERDATAINFO pUserDataInfo2;
NTSTATUS ntStatus;
TRACE((DEBUG_TSHRSRV_FLOW,
"TShrSRV: TSrvInitWDConnectInfo entry\n"));
// For a standard connection we receive client user data as part of the
// GCC connection request. Shadow connections are initiated via RPC and
// the input buffer contains the format sent by the other TS.
if (ioctl == IOCTL_TSHARE_CONF_CONNECT) {
TS_ASSERT(pTSrvInfo->pUserDataInfo);
TS_ASSERT(pTSrvInfo->pUserDataInfo->cbSize);
}
// Allocate a block of memory to receive return UserData from
// WDTShare. This data will subsequently be sent to the client
// via TSrvConfCreateResp.
pUserDataInfo = TSHeapAlloc(0, 128, TS_HTAG_TSS_USERDATA_OUT);
if (pUserDataInfo != NULL) {
// Set the UserData cbSize element. This is so that WDTShare can
// determine if there is sufficient space available to place the
// return data into
pUserDataInfo->cbSize = 128 ;
TRACE((DEBUG_TSHRSRV_DETAIL,
"TShrSRV: Allocated 0x%x bytes to recieve WDTShare return data\n",
pUserDataInfo->cbSize));
// Exchange UserData with WDTShare. If the provided output buffer
// (pUserDataInfo) is large enough then the data will be exchanged
// in one call. If the buffer is not large enough, then it is up to
// WDTShare to tell TShareSRV how to react. For general errors we
// just exit. For STATUS_BUFFER_TOO_SMALL errors, TShareSrv looks at
// the returned cbSize to determine how to adjust the buffer. If
// WDTShare did not increase the cbSize then TShareSrv will increase
// it by a default amount (128 bytes). TShareSrv will use the new value
// to reallocate the output buffer and try the WDTShare call again.
// (Note that TShareSrv will only try this a max of 20 times)
for (i = 0; i < 20; i++) {
TRACE((DEBUG_TSHRSRV_NORMAL, "TShrSRV: Performing connect (size=%ld)\n",
pUserDataInfo->cbSize));
ulBytesReturned = 0;
// Pass the actual client user data to the WD
if (ioctl == IOCTL_TSHARE_CONF_CONNECT) {
ntStatus = IcaStackIoControl(hStack,
ioctl,
pTSrvInfo->pUserDataInfo,
pTSrvInfo->pUserDataInfo->cbSize,
pUserDataInfo,
pUserDataInfo->cbSize,
&ulBytesReturned);
}
// Pass the shadow module data to the WD
else {
ntStatus = IcaStackIoControl(hStack,
ioctl,
pModuleData,
cbModuleData,
pUserDataInfo,
pUserDataInfo->cbSize,
&ulBytesReturned);
}
if (ntStatus != STATUS_BUFFER_TOO_SMALL)
break;
// The output buffer is too small, if WDTShare told us how big to make
// the buffer then we are all set. Otherwise, by default, bump the buffer
// up by 128 bytes
if (ulBytesReturned < sizeof(pUserDataInfo->cbSize))
{
pUserDataInfo->cbSize += 128;
TRACE((DEBUG_TSHRSRV_DEBUG,
"TShrSRV: Buffer too small - increasing it by 128 bytes to %d\n",
pUserDataInfo->cbSize));
}
else
{
TRACE((DEBUG_TSHRSRV_DEBUG,
"TShrSRV: Buffer too small - WDTShare set it to %d bytes\n",
pUserDataInfo->cbSize));
}
pUserDataInfo2 = TSHeapReAlloc(0, pUserDataInfo, pUserDataInfo->cbSize);
if (!pUserDataInfo2)
{
TRACE((DEBUG_TSHRSRV_WARN,
"TShrSRV: Unable to allocate %d byte userData buffer\n"));
break;
}
else {
pUserDataInfo = pUserDataInfo2;
}
}
}
else
{
TRACE((DEBUG_TSHRSRV_WARN,
"TShrSRV: Unable to allocate 0x%x bytes to recieve WDTShare return data\n",
pUserDataInfo->cbSize));
ntStatus = STATUS_NO_MEMORY;
}
// Free the input (client generated) UserData - we don't need it
// lying aroung anymore.
if (pTSrvInfo->pUserDataInfo != NULL) {
TSHeapFree(pTSrvInfo->pUserDataInfo);
pTSrvInfo->pUserDataInfo = NULL;
}
// If we succeeded in the exchange of info, add security info.
if (NT_SUCCESS(ntStatus))
{
TS_ASSERT( pUserDataInfo != NULL );
//
// add user mode security data to the pUserDataInfo if we originally
// received user data from the client.
//
ntStatus = AppendSecurityData(pTSrvInfo, &pUserDataInfo, bGetCert, ppSecInfo);
}
if (!NT_SUCCESS(ntStatus)) {
if (pUserDataInfo != NULL) {
TSHeapFree(pUserDataInfo);
pUserDataInfo = NULL;
}
}
// Return this pointer since the underlying routine does a realloc on it
*ppUserDataInfo = pUserDataInfo;
TRACE((DEBUG_TSHRSRV_FLOW,
"TShrSRV: TSrvInitWDConnectInfo exit - 0x%x\n", ntStatus));
return ntStatus;
}
//*************************************************************
// TSrvShadowTargetConnect
//
// Purpose: Sends the shadow server's certificate and server
// random to the client server for validation, then
// waits for an encrypted client random to be returned.
//
// Return: STATUS_SUCCESS - Success
// other - Failure
//
// History: 4/26/99 jparsons Created
//*************************************************************
NTSTATUS TSrvShadowTargetConnect(
HANDLE hStack,
PTSRVINFO pTSrvInfo,
PBYTE pModuleData,
ULONG cbModuleData)
{
PUSERDATAINFO pUserDataInfo;
NTSTATUS status;
PVOID pSecInfo;
pUserDataInfo = NULL;
status = TSrvInitWDConnectInfo(hStack,
pTSrvInfo,
&pUserDataInfo,
IOCTL_TSHARE_SHADOW_CONNECT,
pModuleData,
cbModuleData,
TRUE,
&pSecInfo);
if (status == STATUS_SUCCESS) {
status = SendSecurityData(hStack, pSecInfo);
if (NT_SUCCESS(status)) {
if (pTSrvInfo->bSecurityEnabled) {
NTSTATUS TempStatus;
// We use the result of GetClientRandom() as the status to
// determine the CreateSessionKeys() IOCTL type. We ignore
// the return from CreateSessionKeys() is the client random
// is not successful.
status = GetClientRandom(hStack, pTSrvInfo, 15000, TRUE);
if (!NT_SUCCESS(status)) {
TRACE((DEBUG_TSHRSRV_ERROR,
"TShrSRV: Could not get client random [%lx]\n",
status));
}
TempStatus = CreateSessionKeys(hStack, pTSrvInfo, status);
if (NT_SUCCESS(status))
status = TempStatus;
}
}
else {
TRACE((DEBUG_TSHRSRV_ERROR,
"TShrSRV: Could not send shadow security info[%lx]\n", status));
}
}
else {
TRACE((DEBUG_TSHRSRV_ERROR,
"TShrSRV: Could not initialize shadow target [%lx]\n", status));
}
if (NT_SUCCESS(status)) {
TRACE((DEBUG_TSHRSRV_NORMAL,
"TShrSRV: Shadow target security exchange complete!\n"));
}
return status;
}
//*************************************************************
//
// TSrvShadowClientConnect
//
// Purpose: Validate the certificate received from the shadow
// client's server. If legit generate and encrypt a
// client random for use by the shadow server
// client.
//
// Return: STATUS_SUCCESS - Success
// other - Failure
//
// History: 4/26/99 jparsons Created
//
//*************************************************************
NTSTATUS TSrvShadowClientConnect(HANDLE hStack, PTSRVINFO pTSrvInfo)
{
CERT_TYPE certType;
ULONG cbServerPubKey;
PBYTE pbServerPubKey = NULL;
ULONG cbServerRandom;
PBYTE pbServerRandom;
PVOID pSecInfo;
PUSERDATAINFO pUserDataInfo;
NTSTATUS status;
pUserDataInfo = NULL;
status = TSrvInitWDConnectInfo(hStack,
pTSrvInfo,
&pUserDataInfo,
IOCTL_TSHARE_SHADOW_CONNECT,
(PBYTE) NULL,
0,
FALSE,
&pSecInfo);
if (status == STATUS_SUCCESS) {
// This is the client passthru stack so validate the shadow server's
// certificate and if good, store the server random.
pbServerRandom = pTSrvInfo->SecurityInfo.KeyPair.serverRandom;
cbServerRandom = sizeof(pTSrvInfo->SecurityInfo.KeyPair.serverRandom);
status = TSrvValidateServerCertificate(
hStack,
&certType,
&cbServerPubKey,
&pbServerPubKey,
cbServerRandom,
pbServerRandom,
15000);
if (NT_SUCCESS(status)) {
TRACE((DEBUG_TSHRSRV_NORMAL,
"TShrSRV: Validated server cert[%s]: PublicKeyLength = %ld\n",
(certType == CERT_TYPE_X509) ? "X509" :
((certType == CERT_TYPE_PROPRIETORY) ? "PROPRIETORY" :
"INVALID"), cbServerPubKey));
// If encryption is enabled, then we need to encrypt a client random
// with the shadow server's public key, and send it.
if (cbServerPubKey != 0) {
BOOL success;
EnterCriticalSection( &g_TSrvCritSect );
success = TSRNG_GenerateRandomBits(
pTSrvInfo->SecurityInfo.KeyPair.clientRandom,
sizeof(pTSrvInfo->SecurityInfo.KeyPair.clientRandom));
LeaveCriticalSection( &g_TSrvCritSect );
if (!success) {
TRACE((DEBUG_TSHRSRV_ERROR,
"TShrSRV: Could not generate a client random!\n"));
}
// We use the result of TSRNG_GenerateRandomBits() to determine the
// CreateSessionKeys() IOCTL type.
status = CreateSessionKeys(hStack, pTSrvInfo,
(success ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL));
// send encrypted client random to the other server
if (NT_SUCCESS(status)) {
status = SendClientRandom(
hStack,
certType,
pbServerPubKey,
cbServerPubKey,
pTSrvInfo->SecurityInfo.KeyPair.clientRandom,
sizeof(pTSrvInfo->SecurityInfo.KeyPair.clientRandom));
}
if (pbServerPubKey != NULL) {
TSHeapFree(pbServerPubKey);
pbServerPubKey = NULL;
}
if (NT_SUCCESS(status)) {
TRACE((DEBUG_TSHRSRV_NORMAL,
"TShrSRV: Shadow client security exchange complete!\n"));
}
}
}
else {
TRACE((DEBUG_TSHRSRV_ERROR,
"TShrSRV: Validation failed on shadow certificate rc=%lx\n",
status));
if (status == STATUS_IO_TIMEOUT) {
status = STATUS_DECRYPTION_FAILED;
}
}
}
else {
TRACE((DEBUG_TSHRSRV_ERROR,
"TShrSRV: Could not initialize shadow client [%lx]\n", status));
}
return status;
}
//*************************************************************
//
// TSrvInitWD()
//
// Purpose: Performs WDTshare initialization
//
// Parameters: IN [pTSrvInfo] - TShareSrv object
// IN OUT [ppUserDataInfo] - pointer to generated user data
//
// Return: STATUS_SUCCESS - Success
// other - Failure
//
// History: 07-17-97 BrianTa Created
//
//*************************************************************
NTSTATUS
TSrvInitWD(IN PTSRVINFO pTSrvInfo, IN OUT PUSERDATAINFO *ppUserDataInfo)
{
NTSTATUS ntStatus;
PVOID pSecData;
TRACE((DEBUG_TSHRSRV_FLOW,
"TShrSRV: TSrvInitWD entry\n"));
// Pass on connection information
TRACE((DEBUG_TSHRSRV_NORMAL,
"TShrSRV: Performing WDTShare connection info exchange\n"));
ntStatus = TSrvInitWDConnectInfo(pTSrvInfo->hStack,
pTSrvInfo,
ppUserDataInfo,
IOCTL_TSHARE_CONF_CONNECT,
NULL, 0, TRUE, &pSecData);
if (!NT_SUCCESS(ntStatus))
{
TRACE((DEBUG_TSHRSRV_DEBUG,
"TShrSRV: WDTShare connection info exchange unsuccessful - 0x%x\n", ntStatus));
}
TRACE((DEBUG_TSHRSRV_FLOW,
"TShrSRV: TSrvInitWD exit - 0x%x\n", ntStatus));
return (ntStatus);
}
//*************************************************************
//
// TSrvCreateGCCDataList()
//
// Purpose: Creates a Gcc UserData indirection list and
// re-bases the UserData data pointers
//
// Parameters: IN [pTSrvInfo] - TShareSrv object
//
// Return: ppDataList
//
// History: 07-17-97 BrianTa Created
//
//*************************************************************
GCCUserData **
TSrvCreateGCCDataList(IN PTSRVINFO pTSrvInfo, PUSERDATAINFO pUserDataInfo)
{
DWORD i;
GCCUserData **ppDataList;
GCCUserData *pUserData;
TRACE((DEBUG_TSHRSRV_FLOW,
"TShrSRV: TSrvCreateGCCDataList entry\n"));
ppDataList = NULL;
TS_ASSERT(pUserDataInfo);
if (pUserDataInfo)
{
TRACE((DEBUG_TSHRSRV_DETAIL, "TShrSRV: Creating UserData list\n"));
TS_ASSERT(pUserDataInfo->ulUserDataMembers > 0);
// Allocate UserData list memory
ppDataList = TSHeapAlloc(HEAP_ZERO_MEMORY,
sizeof(GCCUserData *) * pUserDataInfo->ulUserDataMembers,
TS_HTAG_TSS_USERDATA_LIST);
if (ppDataList)
{
TRACE((DEBUG_TSHRSRV_DETAIL,
"TShrSRV: Allocated 0x%x bytes for 0x%x member UserData array\n",
sizeof(GCCUserData *) * pUserDataInfo->ulUserDataMembers,
pUserDataInfo->ulUserDataMembers));
for (i=0; i<pUserDataInfo->ulUserDataMembers; i++)
{
pUserData = &pUserDataInfo->rgUserData[i];
// Key data rebase
if (pUserData->key.key_type == GCC_OBJECT_KEY)
{
(PUCHAR) pUserData->key.u.object_id.long_string +=
(ULONG_PTR) pUserDataInfo;
}
else
{
(PUCHAR) pUserData->key.u.h221_non_standard_id.octet_string +=
(ULONG_PTR)pUserDataInfo;
}
// Client data ptr, and data rebase
if (pUserData->octet_string)
{
(PUCHAR) pUserData->octet_string +=
(ULONG_PTR)pUserDataInfo;
if (pUserData->octet_string->octet_string)
{
(PUCHAR) pUserData->octet_string->octet_string +=
(ULONG_PTR) pUserDataInfo;
}
}
// Assign the table list entry
ppDataList[i] = pUserData;
}
}
else
{
TRACE((DEBUG_TSHRSRV_WARN,
"TShrSRV: Unable to allocate 0x%x bytes for 0x%x member UserData array\n",
sizeof(GCCUserData *) * pUserDataInfo->ulUserDataMembers,
pUserDataInfo->ulUserDataMembers));
}
}
else
{
TRACE((DEBUG_TSHRSRV_WARN, "TShrSRV: Not creating UserData list - no UserData\n"));
}
TRACE((DEBUG_TSHRSRV_FLOW,
"TShrSRV: TSrvCreateGCCDataList exit = 0x%x\n", ppDataList));
return (ppDataList);
}
//*************************************************************
//
// TSrvConfCreateResp()
//
// Purpose: Performs GCCConferenceCreateResponse
//
// Parameters: IN [pTSrvInfo] - TShareSrv object
//
// Return: STATUS_SUCCESS - Success
// other - Failure
//
// History: 07-17-97 BrianTa Created
//
//*************************************************************
NTSTATUS
TSrvConfCreateResp(IN OUT PTSRVINFO pTSrvInfo)
{
NTSTATUS ntStatus;
GCCError GCCrc;
GCCUserData **pDataList;
PUSERDATAINFO pUserDataInfo;
TRACE((DEBUG_TSHRSRV_FLOW,
"TShrSRV: TSrvConfCreateResp entry\n"));
ntStatus = pTSrvInfo->ntStatus;
pUserDataInfo = NULL;
if (NT_SUCCESS(ntStatus))
{
TRACE((DEBUG_TSHRSRV_DEBUG, "TShrSRV: Attempting ConfCreate response\n"));
// Perform WDTShare connection initialization
ntStatus = TSrvInitWD(pTSrvInfo, &pUserDataInfo);
pTSrvInfo->ntStatus = ntStatus;
if (NT_SUCCESS(ntStatus))
{
// The exchange of info with WDTShare has proceeded successfully,
// So we can now create a digestable data transfer structure
// for GCC
pDataList = TSrvCreateGCCDataList(pTSrvInfo, pUserDataInfo);
if (pDataList)
{
// Accept the conference creation request
TRACE((DEBUG_TSHRSRV_NORMAL, "TShrSRV: Accepting conference domain %p\n",
pTSrvInfo->hDomain));
GCCrc = GCCConferenceCreateResponse(
NULL, // conference_modifier
pTSrvInfo->hDomain, // domain handle
0, // use_password_in_the_clear
NULL, // domain_parameters
0, // number_of_network_addresses
NULL, // local_network_address_list
1, // number_of_user_data_members
(GCCUserData**)pDataList, // user_data_list
GCC_RESULT_SUCCESSFUL); // reason
TSrvDumpGCCRCDetails(GCCrc,
"GCCConferenceCreateResponse");
if (GCCrc == GCC_NO_ERROR)
ntStatus = STATUS_SUCCESS;
else
ntStatus = STATUS_REQUEST_NOT_ACCEPTED;
TSHeapFree(pDataList);
}
else
{
ntStatus = STATUS_NO_MEMORY;
}
}
else
{
// Conference is being rejected
TRACE((DEBUG_TSHRSRV_NORMAL, "TShrSRV: Rejecting conference domain %p - 0x%x\n",
pTSrvInfo->hDomain, pTSrvInfo->ntStatus));
GCCrc = GCCConferenceCreateResponse(
NULL, // conference_modifier
pTSrvInfo->hDomain, // domain
0, // use_password_in_the_clear
NULL, // domain_parameters
0, // number_of_network_addresses
NULL, // local_network_address_list
1, // number_of_user_data_members
NULL, // user_data_list
GCC_RESULT_USER_REJECTED); // reason
TSrvDumpGCCRCDetails(GCCrc,
"TShrSRV: GCCConferenceCreateResponse\n");
// Return the original failure status back to the caller
ntStatus = pTSrvInfo->ntStatus;
}
}
else {
TRACE((DEBUG_TSHRSRV_ERROR,
"TShrSRV: Connect failure, could not generate response: %lx\n",
ntStatus));
}
if (NT_SUCCESS(ntStatus))
{
//
// if we successfully sent the conference connect response, then
// check security response (only if we need to).
//
if (pTSrvInfo->bSecurityEnabled) {
NTSTATUS TempStatus;
// We use the result of GetClientRandom() as the status to
// determine the CreateSessionKeys() IOCTL type. We ignore the
// return from CreateSessionKeys() if the client random is
// not successful.
ntStatus = GetClientRandom(pTSrvInfo->hStack, pTSrvInfo, 60000,
FALSE);
TempStatus = CreateSessionKeys(pTSrvInfo->hStack, pTSrvInfo,
ntStatus);
if (NT_SUCCESS(ntStatus))
ntStatus = TempStatus;
}
}
// If we still have a UserData structure, free it, we no longer need it.
if (pUserDataInfo)
{
TSHeapFree(pUserDataInfo);
pUserDataInfo = NULL;
}
TRACE((DEBUG_TSHRSRV_FLOW,
"TShrSRV: TSrvConfCreateResp exit = 0x%x\n", ntStatus));
return (ntStatus);
}
//*************************************************************
//
// TSrvConfDisconnectReq()
//
// Purpose: Performs GCCConferenceTerminateRequest
//
// Parameters: IN [pTSrvInfo] - TShareSrv object
// IN [ulReason] - Reason code
//
// Return: STATUS_SUCCESS - Success
// other - Failure
//
// History: 07-17-97 BrianTa Created
//
//*************************************************************
NTSTATUS
TSrvConfDisconnectReq(IN PTSRVINFO pTSrvInfo,
IN ULONG ulReason)
{
GCCError GCCrc;
NTSTATUS ntStatus;
TRACE((DEBUG_TSHRSRV_FLOW,
"TShrSRV: TSrvConfDisconnectReq entry\n"));
ntStatus = STATUS_REQUEST_ABORTED;
TRACE((DEBUG_TSHRSRV_NORMAL,
"TShrSRV: Conf termination - domain %p - reason 0x%x\n",
pTSrvInfo->hDomain, ulReason));
GCCrc = GCCConferenceTerminateRequest(pTSrvInfo->hIca, pTSrvInfo->hDomain,
pTSrvInfo->hConnection, ulReason);
TSrvDumpGCCRCDetails(GCCrc,
"GCCConferenceTerminateRequest");
if (GCCrc == GCC_NO_ERROR)
ntStatus = STATUS_SUCCESS;
TRACE((DEBUG_TSHRSRV_FLOW,
"TShrSRV: TSrvConfDisconnectReq exit = 0x%x\n", ntStatus));
return (ntStatus);
}
//-----
#if DBG
//-----
//*************************************************************
//
// TSrvBuildNameFromGCCConfName()
//
// Purpose: Build a traceable conference name from
// a GCC name
//
// Parameters: IN [gccName] - GCCConferenceName
// OUT [pConfName] - Traceable name
//
// Return: STATUS_SUCCESS - Success
// other - Failure
//
// History: 07-17-97 BrianTa Created
//
//*************************************************************
void
TSrvBuildNameFromGCCConfName(IN GCCConferenceName *gccName,
OUT PCHAR pConfName)
{
int i;
// The text represenation of a GCC conference name is:
//
// <text_string> : (<numeric_string>)
i = 0;
while (gccName->text_string[i] != 0x0000)
{
pConfName[i] = (CHAR)gccName->text_string[i];
i++;
}
pConfName[i] = '\0';
}
//*************************************************************
//
// TSrvDumpCreateIndDetails()
//
// Purpose: Dumps out GCC_CREATE_IND details
//
// Parameters: IN [pCreateMessage] - CreateIndicationMessage
//
// Return: void
//
// History: 07-17-97 BrianTa Created
//
//*************************************************************
void
TSrvDumpCreateIndDetails(IN CreateIndicationMessage *pCreateMessage)
{
CHAR name[MAX_CONFERENCE_NAME_LEN];
if (pCreateMessage->conductor_privilege_list == NULL)
{
TRACE((DEBUG_TSHRSRV_DETAIL,
"TShrSRV: Conductor privilege list is NULL\n"));
}
else
{
TRACE((DEBUG_TSHRSRV_DETAIL,
"TShrSRV: Conductor priv, terminate allowed 0x%x\n",
pCreateMessage->conductor_privilege_list->terminate_is_allowed));
}
if (pCreateMessage->conducted_mode_privilege_list == NULL)
{
TRACE((DEBUG_TSHRSRV_DETAIL,
"TShrSRV: Conducted mode privilege list is NULL\n"));
}
else
{
TRACE((DEBUG_TSHRSRV_DETAIL,
"TShrSRV: Conducted mode priv, terminate allowed 0x%x\n",
pCreateMessage->conducted_mode_privilege_list->terminate_is_allowed));
}
if (pCreateMessage->non_conducted_privilege_list == NULL)
{
TRACE((DEBUG_TSHRSRV_DETAIL,
"TShrSRV: Non-conducted mode privilege list is NULL\n"));
}
else
{
TRACE((DEBUG_TSHRSRV_DETAIL,
"TShrSRV: non-conducted priv, terminate allowed 0x%x\n",
pCreateMessage->non_conducted_privilege_list->terminate_is_allowed));
}
if (pCreateMessage->conference_name.text_string == NULL)
{
TRACE((DEBUG_TSHRSRV_DETAIL,
"TShrSRV: NULL conf name\n"));
}
else
{
TSrvBuildNameFromGCCConfName(&(pCreateMessage->conference_name), name);
TRACE((DEBUG_TSHRSRV_DETAIL,
"TShrSRV: Conf name '%s'\n", name));
}
}
//*************************************************************
//
// TSrvDumpGCCRCDetails()
//
// Purpose: Dumps out GCC return code details
//
// Parameters: IN [GCCrc] - GCC return code
// IN [pszText] - var text
//
// Return: void
//
// History: 07-17-97 BrianTa Created
//
//*************************************************************
void
TSrvDumpGCCRCDetails(IN GCCError gccRc,
IN PCHAR pszText)
{
int i;
PCHAR pszMessageText;
pszMessageText = "UNKNOWN_GCC_RC";
for (i=0; i<sizeof(GCCReturnCodeTBL) / sizeof(GCCReturnCodeTBL[0]); i++)
{
if (GCCReturnCodeTBL[i].gccRC == gccRc)
{
pszMessageText = GCCReturnCodeTBL[i].pszMessageText;
break;
}
}
TRACE((DEBUG_TSHRSRV_DETAIL,
"TShrSRV: %s - GCC rc 0x%x (%s)\n",
pszText, gccRc, pszMessageText));
}
//*************************************************************
//
// TSrvDumpGCCReasonDetails()
//
// Purpose: Dumps out GCC reason code details
//
// Parameters: IN [gccReason] - GCC reason code
// IN [pszText] - var text
//
// Return: void
//
// History: 07-17-97 BrianTa Created
//
//*************************************************************
void
TSrvDumpGCCReasonDetails(IN GCCReason gccReason,
IN PCHAR pszText)
{
int i;
PCHAR pszMessageText;
pszMessageText = "UNKNOWN_GCC_REASON";
for (i=0; i<sizeof(GCCReasonTBL) / sizeof(GCCReasonTBL[0]); i++)
{
if (GCCReasonTBL[i].gccReason == gccReason)
{
pszMessageText = GCCReasonTBL[i].pszMessageText;
break;
}
}
TRACE((DEBUG_TSHRSRV_DETAIL,
"TShrSRV: %s - GCC reason 0x%x (%s)\n",
pszText, gccReason, pszMessageText));
}
//*************************************************************
//
// TSrvDumpCallBackMessage()
//
// Purpose: Dumps out GCC CallBackMessage details
//
// Parameters: IN [pGCCMessage] - GCCMessage
//
// Return: void
//
// History: 07-17-97 BrianTa Created
//
//*************************************************************
void
TSrvDumpCallBackMessage(IN GCCMessage *pGCCMessage)
{
int i;
PCHAR pszMessageText;
pszMessageText = "UNKNOWN_GCC_MESSAGE";
for (i=0; i<sizeof(GCCCallBackTBL) / sizeof(GCCCallBackTBL[0]); i++)
{
if (GCCCallBackTBL[i].message_type == pGCCMessage->message_type)
{
pszMessageText = GCCCallBackTBL[i].pszMessageText;
break;
}
}
TRACE((DEBUG_TSHRSRV_DEBUG,
"TShrSRV: GCCCallback message 0x%x (%s) received\n",
pGCCMessage->message_type, pszMessageText));
}
//*************************************************************
//
// TSrvDumpUserData()
//
// Purpose: Dumps out GCC UserData details
//
// Parameters: IN [pCreateMessage] - GCCMessage
//
// Return: void
//
// History: 07-17-97 BrianTa Created
//
//*************************************************************
void
TSrvDumpUserData(IN CreateIndicationMessage *pCreateMessage)
{
int i;
ULONG ulUserDataSize;
GCCUserData *pClientUserData;
TRACE((DEBUG_TSHRSRV_DETAIL,
"TShrSRV: number_of_user_data_members = 0x%x\n",
pCreateMessage->number_of_user_data_members));
for (i=0; i<pCreateMessage->number_of_user_data_members; i++)
{
pClientUserData = pCreateMessage->user_data_list[i];
if (pClientUserData != NULL)
{
if (pClientUserData->key.key_type == GCC_OBJECT_KEY)
{
TRACE((DEBUG_TSHRSRV_DETAIL,
"TShrSRV: key_type = 0x%x (GCC_OBJECT_KEY)\n",
pClientUserData->key.key_type));
TRACE((DEBUG_TSHRSRV_DETAIL,
"TShrSRV: Key long_string_length = 0x%x\n",
pClientUserData->key.u.object_id.long_string_length));
}
else
{
TRACE((DEBUG_TSHRSRV_DETAIL,
"TShrSRV: Key_type = 0x%x (GCC_H221_NONSTANDARD_KEY)\n",
pClientUserData->key.key_type));
TRACE((DEBUG_TSHRSRV_DETAIL,
"TShrSRV: key long_string_length = 0x%x\n",
pClientUserData->key.u.h221_non_standard_id.octet_string_length));
}
if (pClientUserData->octet_string)
{
TRACE((DEBUG_TSHRSRV_DETAIL,
"TShrSRV: data long_string_length = 0x%x\n",
pClientUserData->octet_string->octet_string_length));
}
else
{
TRACE((DEBUG_TSHRSRV_DETAIL, "TShrSRV: No data\n"));
}
}
else
{
TRACE((DEBUG_TSHRSRV_DETAIL, "TShrSRV: No key\n"));
}
}
}
#endif // DBG