/****************************************************************************/ // tsrvcom.c // // RDPWSX routines for lower-layer (GCC, RDPWD) communications support // // Copyright (C) 1991-2000 Microsoft Corporation /****************************************************************************/ #include #include #include #include <_TSrvInfo.h> #include <_TSrvCom.h> #include #include // 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; inumber_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; iulUserDataMembers; 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; iulUserDataMembers; 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: // // : () 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; imessage_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; inumber_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