/***********************************************************************
 * 
 *  Copyright (C) 2006 Novell, Inc. All Rights Reserved.
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; version 2.1
 *  of the License.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, Novell, Inc.
 * 
 *  To contact Novell about this file by physical or electronic mail, 
 *  you may find current contact information at www.novell.com.
 * 
 *  Author: Juan Carlos Luciani <jluciani@novell.com>
 *
 ***********************************************************************/


//===[ Include files ]=====================================================

#include "internal.h"

//===[ Type definitions ]==================================================

#define INITIAL_RESPONSE_DATA_BUF_SIZE 1028
#define INCREMENT_RESPONSE_DATA_BUF_SIZE 256

#define MAX_RPC_RETRIES 3

//===[ Function prototypes ]===============================================

//===[ Global variables ]==================================================

//++=======================================================================
static
CasaStatus
CopyMultiToWideAlloc(
   IN    char *pMulti,
   IN    int multiSize,
   INOUT LPWSTR *ppWide,
   INOUT int *pWideSize)
//
//  Arguments: 
//
//  Returns:   
//
//  Abstract:  
//
//  Notes:
//
// L2
//=======================================================================--
{
   int      retStatus;
   int      size, i;

   DbgTrace(2, "-CopyMultiToWideAlloc- Start\n", 0);

   size = (multiSize + 1) * sizeof(WCHAR);

   if ((*ppWide = (PWCHAR) malloc(size)) != NULL)
   {
      for (i = 0; i < multiSize; i++)
      {
         *(*ppWide + i) = (unsigned char) *(pMulti + i);
      }

      *(*ppWide + i) = L'\0';

      if (pWideSize)
      {
         *pWideSize = size - sizeof(WCHAR);
      }

      retStatus = CASA_STATUS_SUCCESS;
   }
   else
   {
      retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
                                  CASA_FACILITY_AUTHTOKEN,
                                  CASA_STATUS_INSUFFICIENT_RESOURCES);
   }

   DbgTrace(2, "-CopyMultiToWideAlloc- End, retStatus = %08X\n", retStatus);

   return retStatus;
}


//++=======================================================================
static
CasaStatus
CopyWideToMultiAlloc(
   IN    LPWSTR pWide,
   IN    int wideSize,
   INOUT char **ppMulti,
   INOUT int *pMultiSize)
//
//  Arguments: 
//
//  Returns:   
//
//  Abstract:  
//
//  Notes:
//
// L2
//=======================================================================--
{
   int      retStatus;
   int      size, i;

   DbgTrace(2, "-CopyWideToMultiAlloc- Start\n", 0);

   size = wideSize + 1;

   if ((*ppMulti = malloc(size)) != NULL)
   {
      for (i = 0; i < wideSize; i++)
      {
         *(*ppMulti + i) = (char) *(pWide + i);
      }

      *(*ppMulti + i) = '\0';

      if (pMultiSize)
      {
         *pMultiSize = size - 1;
      }

      retStatus = CASA_STATUS_SUCCESS;
   }
   else
   {
      retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
                                  CASA_FACILITY_AUTHTOKEN,
                                  CASA_STATUS_INSUFFICIENT_RESOURCES);
   }

   DbgTrace(2, "-CopyWideToMultiAlloc- End, retStatus = %08X\n", retStatus);

   return retStatus;
}


//++=======================================================================
RpcSession*
OpenRpcSession(
   IN    char *pHostName,
   IN    uint16_t hostPort)
//
//  Arguments: 
//
//  Returns:   
//
//  Abstract:  
//
//  Notes:
//
// L2
//=======================================================================--
{
   RpcSession  *pSession;
   bool        success = false;

   DbgTrace(1, "-OpenRpcSession- Start\n", 0);

   // Allocate space for the session
   pSession = (RpcSession*) malloc(sizeof(*pSession));
   if (pSession)
   {
      // Zero the session structure
      memset(pSession, 0, sizeof(*pSession));

      // Save copy of the hostname
      pSession->pHostName = malloc(strlen(pHostName) + 1);
      if (pSession->pHostName)
      {
         strcpy(pSession->pHostName, pHostName);

         // Open a Winhttp session
         pSession->hSession = WinHttpOpen(L"CASA Client/1.0",
                                          WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
                                          WINHTTP_NO_PROXY_NAME,
                                          WINHTTP_NO_PROXY_BYPASS,
                                          0);
         if (pSession->hSession)
         {
            LPWSTR   pWideHostName;
            int      wideHostLen;

            // Session opened, now convert the host name to Unicode so that
            // we can open a connection.
            if (CopyMultiToWideAlloc(pHostName,
                                     (int) strlen(pHostName),
                                     &pWideHostName,
                                     &wideHostLen) == CASA_STATUS_SUCCESS)
            {
               // Now open connection
               pSession->hConnection = WinHttpConnect(pSession->hSession,
                                                      pWideHostName,
                                                      hostPort,
                                                      0);
               if (pSession->hConnection == NULL)
               {
                  DbgTrace(0, "-OpenRpcSession- Failed to open connection, error = %d\n", GetLastError());
               }
               else
               {
                  success = true;
               }

               // Free the host name wide string buffer
               free(pWideHostName);
            }
            else
            {
               DbgTrace(0, "-OpenRpcSession- Error converting host name to wide string\n", 0);
            }
         }
         else
         {
            DbgTrace(0, "-OpenRpcSession- Failed to open session, error = %d\n", GetLastError());
         }
      }
      else
      {
         DbgTrace(0, "-OpenRpcSession- Failed to allocate buffer for host name\n", 0);
      }
   }
   else
   {
      DbgTrace(0, "-OpenRpcSession- Failed to allocate buffer for rpc session\n", 0);
   }

   // Clean up if we did not succeed
   if (!success)
   {
      if (pSession)
      {
         if (pSession->hConnection)
            WinHttpCloseHandle(pSession->hConnection);

         if (pSession->hSession)
            WinHttpCloseHandle(pSession->hSession);

         if (pSession->pHostName)
            free(pSession->pHostName);

         free(pSession);
         pSession = NULL;
      }
   }

   DbgTrace(2, "-OpenRpcSession- End, pSession = %08X\n", pSession);

   return pSession;
}


//++=======================================================================
void
CloseRpcSession(
   IN    RpcSession *pSession)
//
//  Arguments: 
//
//  Returns:   
//
//  Abstract:  
//
//  Notes:
//
// L2
//=======================================================================--
{
   DbgTrace(1, "-CloseRpcSession- Start\n", 0);

   // Close the connection handle
   WinHttpCloseHandle(pSession->hConnection);

   // Close the session handle
   WinHttpCloseHandle(pSession->hSession);

   // Free hostname buffer if necessary
   if (pSession->pHostName)
      free(pSession->pHostName);

   // Free the space allocated for the session
   free(pSession);

   DbgTrace(1, "-CloseRpcSession- End\n", 0);
}


//++=======================================================================
static
void CALLBACK
SecureFailureStatusCallback(
   IN    HINTERNET hRequest,
   IN    DWORD *pContext,
   IN    DWORD internetStatus,
   IN    LPVOID pStatusInformation,
   IN    DWORD statusInformationLength)
//
//  Arguments: 
//
//  Returns:   
//
//  Abstract:  
//
//  Notes:
//
// L0
//=======================================================================--
{
   DbgTrace(1, "-SecureFailureStatusCallback- Start\n", 0);

   // Only deal with failures related to certificates
   if (internetStatus == WINHTTP_CALLBACK_STATUS_SECURE_FAILURE)
   {
      // Save the specific failure status
      *pContext = *(DWORD*) pStatusInformation;
   }

   DbgTrace(1, "-SecureFailureStatusCallback- End\n", 0);
}


//++=======================================================================
static
CasaStatus
InternalRpc(
   IN    RpcSession *pSession,
   IN    char *pMethod,
   IN    long flags,
   IN    char *pRequestData,
   INOUT char **ppResponseData,
   INOUT int *pResponseDataLen)
//
//  Arguments: 
//
//  Returns:   
//
//  Abstract:  
//
//  Notes:
//
// L2
//=======================================================================--
{
#define CASA_STATUS_INVALID_SERVER_CERTIFICATE CASA_STATUS_UNSUCCESSFUL // temporary until casa_status.h is updated

   CasaStatus  retStatus = CASA_STATUS_SUCCESS;
   char        rpcTarget[256];
   LPWSTR      pWideRpcTarget;
   int         wideRpcTargetLen;
   WCHAR       sendHeaders[] = L"Content-Type: text/html";
   DWORD       securityFailureStatusFlags;
   int         retriesAllowed = 1;
   bool        attemptRetry;

   DbgTrace(1, "-InternalRpc- Start\n", 0);

   // Initialize output parameter
   *ppResponseData = NULL;

   // Create rpc target string and convert it to a wide string
   sprintf(rpcTarget, "CasaAuthTokenSvc/Rpc?method=%s", pMethod);
   retStatus = CopyMultiToWideAlloc(rpcTarget,
                                    (int) strlen(rpcTarget),
                                    &pWideRpcTarget,
                                    &wideRpcTargetLen);
   if (CASA_SUCCESS(retStatus))
   {
      HINTERNET   hRequest;

      do
      {
         // Forget about having been told to retry
         attemptRetry = false;

         // Open a request handle
         hRequest = WinHttpOpenRequest(pSession->hConnection,
                                       L"POST",
                                       pWideRpcTarget,
                                       NULL,
                                       WINHTTP_NO_REFERER,
                                       WINHTTP_DEFAULT_ACCEPT_TYPES,
                                       flags & SECURE_RPC_FLAG? WINHTTP_FLAG_REFRESH | WINHTTP_FLAG_SECURE : WINHTTP_FLAG_REFRESH);
         if (hRequest)
         {
            int   reqDataLen = (int) strlen(pRequestData);

            // Check if we need to set options to deal with secure connections
            if (flags & SECURE_RPC_FLAG)
            {
               // We are using secure connections, now proceed based on whether or not
               // we are configured to allow invalid certificates.
               if (flags & ALLOW_INVALID_CERTS_RPC_FLAG
                   || (flags & ALLOW_INVALID_CERTS_USER_APPROVAL_RPC_FLAG
                       && InvalidCertsFromHostAllowed(pSession->pHostName)))
               {
                  DWORD secFlags = SECURITY_FLAG_IGNORE_CERT_CN_INVALID | SECURITY_FLAG_IGNORE_UNKNOWN_CA;

                  // We are configured to allow invalid certificates, inform the HTTP stack.
                  if (WinHttpSetOption(hRequest,
                                       WINHTTP_OPTION_SECURITY_FLAGS,
                                       &secFlags,
                                       sizeof(secFlags)) == FALSE)
                  {
                     DbgTrace(0, "-InternalRpc- Failed setting options to ignore invalid certs, error = %d\n", GetLastError());
                  }
               }
               else
               {
                  // We are not configured to allow invalid certificates, set a callback handler
                  // to detect invalid certificate conditions.
                  if (WinHttpSetStatusCallback(hRequest,
                                               SecureFailureStatusCallback,
                                               WINHTTP_CALLBACK_FLAG_SECURE_FAILURE,
                                               (DWORD_PTR) NULL) == WINHTTP_INVALID_STATUS_CALLBACK)
                  {
                     DbgTrace(0, "-InternalRpc- Failed setting status callback, error = %d\n", GetLastError());
                  }
               }
            }

            // Send the request
            securityFailureStatusFlags = 0;
            if (WinHttpSendRequest(hRequest,
                                   sendHeaders,
                                   -1,
                                   pRequestData,
                                   reqDataLen,
                                   reqDataLen,
                                   (DWORD_PTR) &securityFailureStatusFlags))
            {
               // Request sent, now await for the response.
               if (WinHttpReceiveResponse(hRequest, NULL))
               {
                  WCHAR httpCompStatus[4] = {0};
                  DWORD httpCompStatusLen = sizeof(httpCompStatus);

                  // Response received, make sure that it completed successfully.
                  if (WinHttpQueryHeaders(hRequest,
                                          WINHTTP_QUERY_STATUS_CODE,
                                          NULL,
                                          &httpCompStatus,
                                          &httpCompStatusLen,
                                          WINHTTP_NO_HEADER_INDEX))
                  {
                     // Check that the request completed successfully
                     if (memcmp(httpCompStatus, L"200", sizeof(httpCompStatus)) == 0)
                     {
                        char  *pResponseData;
                        int   responseDataBufSize = INITIAL_RESPONSE_DATA_BUF_SIZE;      
                        int   responseDataRead = 0;

                        // Now read the response data, to do so we need to allocate a buffer.
                        pResponseData = (char*) malloc(INITIAL_RESPONSE_DATA_BUF_SIZE);
                        if (pResponseData)
                        {
                           char     *pCurrLocation = pResponseData;
                           DWORD    bytesRead;

                           do
                           {
                              bytesRead = 0;
                              if (WinHttpReadData(hRequest,
                                                  (LPVOID) pCurrLocation,
                                                  responseDataBufSize - responseDataRead,
                                                  &bytesRead))
                              {
                                 pCurrLocation += bytesRead;
                                 responseDataRead += bytesRead;

                                 // Check if we need to allocate a larger buffer
                                 if (responseDataRead == responseDataBufSize)
                                 {
                                    char  *pTmpBuf;

                                    // We need to upgrade the receive buffer
                                    pTmpBuf = (char*) malloc(responseDataBufSize + INCREMENT_RESPONSE_DATA_BUF_SIZE);
                                    if (pTmpBuf)
                                    {
                                       memcpy(pTmpBuf, pResponseData, responseDataBufSize);
                                       free(pResponseData);
                                       pResponseData = pTmpBuf;
                                       pCurrLocation = pResponseData + responseDataBufSize;
                                       responseDataBufSize += INCREMENT_RESPONSE_DATA_BUF_SIZE;
                                    }
                                    else
                                    {
                                       DbgTrace(0, "-InternalRpc- Buffer allocation failure\n", 0);
                                       retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
                                                                   CASA_FACILITY_AUTHTOKEN,
                                                                   CASA_STATUS_INSUFFICIENT_RESOURCES);
                                    }
                                 }
                              }
                              else
                              {
                                 DbgTrace(0, "-InternalRpc- Failed reading response data, error = %d\n", GetLastError());
                                 retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
                                                             CASA_FACILITY_AUTHTOKEN,
                                                             CASA_STATUS_UNSUCCESSFUL);
                              }
                           } while (CASA_SUCCESS(retStatus)
                                    && bytesRead != 0);

                           // Check if the response data was successfully received
                           if (CASA_SUCCESS(retStatus))
                           {
                              // The response data was received, return it to the caller.
                              *ppResponseData = pResponseData;
                              *pResponseDataLen = responseDataRead; 
                           }
                           else
                           {
                              // Failed to receive the response data, free the allocated buffer.
                              free(pResponseData);
                           }
                        }
                        else
                        {
                           DbgTrace(0, "-InternalRpc- Buffer allocation failure\n", 0);
                           retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
                                                       CASA_FACILITY_AUTHTOKEN,
                                                       CASA_STATUS_INSUFFICIENT_RESOURCES);
                        }
                     }
                     else
                     {
                        DbgTrace(0, "-InternalRpc- HTTP request did not complete successfully, status = %S\n", httpCompStatus);
                        retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
                                                    CASA_FACILITY_AUTHTOKEN,
                                                    CASA_STATUS_UNSUCCESSFUL);
                     }
                  }
                  else
                  {
                     DbgTrace(0, "-InternalRpc- Unable to obtain http request completion status, error = %d\n", GetLastError());
                     retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
                                                 CASA_FACILITY_AUTHTOKEN,
                                                 CASA_STATUS_UNSUCCESSFUL);
                  }
               }
               else
               {
                  DbgTrace(0, "-InternalRpc- Unable to receive response, error = %d\n", GetLastError());
                  retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
                                              CASA_FACILITY_AUTHTOKEN,
                                              CASA_STATUS_UNSUCCESSFUL);
               }
            }
            else
            {
               int   error = GetLastError();

               if (error == ERROR_WINHTTP_CANNOT_CONNECT)
               {
                  DbgTrace(0, "-InternalRpc- Unable to connect to server\n", 0);
                  retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
                                              CASA_FACILITY_AUTHTOKEN,
                                              CASA_STATUS_AUTH_SERVER_UNAVAILABLE);
               }
               else if (error == ERROR_WINHTTP_SECURE_FAILURE)
               {
                  DbgTrace(1, "-InternalRpc- Secure connection failure, flags = %0x\n", securityFailureStatusFlags);

                  // Try to deal with the issue
                  if ((securityFailureStatusFlags & ~(WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA
                                                      | WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID
                                                      | WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID)) == 0
                      && flags & ALLOW_INVALID_CERTS_USER_APPROVAL_RPC_FLAG)
                  {
                     WINHTTP_CERTIFICATE_INFO certInfo;
                     DWORD certInfoLen = sizeof(certInfo);

                     // The failure was due to an invalid CN, CA, or both.
                     //
                     // Obtain information about the server certificate to give user
                     // the choice of accepting it.
                     if (WinHttpQueryOption(hRequest,
                                            WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT,
                                            &certInfo,
                                            &certInfoLen)
                         && certInfo.lpszSubjectInfo != NULL
                         && certInfo.lpszIssuerInfo != NULL)
                     {
                        char  *pSubjectInfo;
                        int   subjectInfoLen;

                        // Convert the subjectInfo to multi-byte
                        retStatus = CopyWideToMultiAlloc(certInfo.lpszSubjectInfo,
                                                         (int) wcslen(certInfo.lpszSubjectInfo),
                                                         &pSubjectInfo,
                                                         &subjectInfoLen);
                        if (CASA_SUCCESS(retStatus))
                        {
                           char  *pIssuerInfo;
                           int   issuerInfoLen;

                           // Convert the issuerInfo to multi-byte
                           retStatus = CopyWideToMultiAlloc(certInfo.lpszIssuerInfo,
                                                            (int) wcslen(certInfo.lpszIssuerInfo),
                                                            &pIssuerInfo,
                                                            &issuerInfoLen);
                           if (CASA_SUCCESS(retStatus))
                           {
                              long  invalidCertFlags = 0;

                              // Setup the invalid cert flags
                              if (securityFailureStatusFlags & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA)
                                 invalidCertFlags |= INVALID_CERT_CA_FLAG;

                              if (securityFailureStatusFlags & WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID)
                                 invalidCertFlags |= INVALID_CERT_CN_FLAG;

                              if (securityFailureStatusFlags & WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID)
                                 invalidCertFlags |= INVALID_CERT_DATE_FLAG;

                              // Give user the choice to accept the certificate
                              if (UserApprovedCert(pSession->pHostName,
                                                   pSubjectInfo,
                                                   pIssuerInfo,
                                                   invalidCertFlags))
                              {
                                 DbgTrace(1, "-InternalRpc- User approved invalid certificate from %s\n", pSession->pHostName);

                                 // tbd - Investigate if there is a way to set the accepted certificate in a store so that
                                 // it can be utilized by the SSL stack directly. This would be a better method for dealing with
                                 // this issue.

                                 AllowInvalidCertsFromHost(pSession->pHostName);

                                 // Try to retry the request
                                 attemptRetry = true;
                              }
                              else
                              {
                                 DbgTrace(1, "-InternalRpc- User did not approve invalid certificate from %s\n", pSession->pHostName);

                                 retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
                                                             CASA_FACILITY_AUTHTOKEN,
                                                             CASA_STATUS_INVALID_SERVER_CERTIFICATE);
                              }

                              // Free the buffer containing the issuerInfo
                              free(pIssuerInfo);
                           }

                           // Free the buffer containing the subjectInfo
                           free(pSubjectInfo);
                        }

                        // Free necessary certificate information
                        if (certInfo.lpszSubjectInfo) LocalFree(certInfo.lpszSubjectInfo);
                        if (certInfo.lpszIssuerInfo) LocalFree(certInfo.lpszIssuerInfo);
                        if (certInfo.lpszProtocolName) LocalFree(certInfo.lpszProtocolName);
                        if (certInfo.lpszSignatureAlgName) LocalFree(certInfo.lpszSignatureAlgName);
                        if (certInfo.lpszEncryptionAlgName) LocalFree(certInfo.lpszEncryptionAlgName);
                     }
                     else
                     {
                        DbgTrace(0, "-InternalRpc- Unable to obtain server certificate struct, error = %0x\n", GetLastError());
                     }
                  }
                  else
                  {
                     // Decided to no give the user a choice to accept invalid server certificate
                     retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
                                                 CASA_FACILITY_AUTHTOKEN,
                                                 CASA_STATUS_INVALID_SERVER_CERTIFICATE);
                  }
               }
               else
               {
                  DbgTrace(0, "-InternalRpc- Unsuccessful send http request, error = %d\n", error);
                  retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
                                              CASA_FACILITY_AUTHTOKEN,
                                              CASA_STATUS_UNSUCCESSFUL);
               }
            }

            // Close the request handle
            WinHttpCloseHandle(hRequest);
         }
         else
         {
            DbgTrace(0, "-InternalRpc- Unable to open http request, error = %d\n", GetLastError());
            retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
                                        CASA_FACILITY_AUTHTOKEN,
                                        CASA_STATUS_UNSUCCESSFUL);
         }
      } while (attemptRetry && retriesAllowed--);

      // Free the rpc target wide string buffer
      free(pWideRpcTarget);
   }
   else
   {
      DbgTrace(0, "-InternalRpc- Error converting method name to wide string\n", 0);
   }

   DbgTrace(1, "-InternalRpc- End, retStatus = %d\n", retStatus);

   return retStatus;
}


//++=======================================================================
CasaStatus
Rpc(
   IN    RpcSession *pSession,
   IN    char *pMethod,
   IN    long flags,
   IN    char *pRequestData,
   INOUT char **ppResponseData,
   INOUT int *pResponseDataLen)
//
//  Arguments: 
//
//  Returns:   
//
//  Abstract:  
//
//  Notes:
//
// L2
//=======================================================================--
{
   CasaStatus  retStatus;
   int         retries = 0;

   DbgTrace(1, "-Rpc- Start\n", 0);

   // Retry the RPC as needed
   do
   {
      // Issue the RPC
      retStatus = InternalRpc(pSession,
                              pMethod,
                              flags,
                              pRequestData,
                              ppResponseData,
                              pResponseDataLen);

      // Account for this try
      retries ++;

   } while (CasaStatusCode(retStatus) == CASA_STATUS_AUTH_SERVER_UNAVAILABLE
            && retries < MAX_RPC_RETRIES);

   DbgTrace(1, "-Rpc- End, retStatus = %d\n", retStatus);

   return retStatus;
}


//++=======================================================================
CasaStatus
InitializeRpc(void)
//
//  Arguments: 
//
//  Returns:   
//
//  Abstract:  
//
//  Notes:
//
// L2
//=======================================================================--
{
   CasaStatus  retStatus = CASA_STATUS_SUCCESS;

   DbgTrace(1, "-InitializeRpc- Start\n", 0);

   // Nothing to do for windows

   DbgTrace(1, "-InitializeRpc- End, retStatus = %08X\n", retStatus);

   return retStatus;
}


//++=======================================================================
//++=======================================================================
//++=======================================================================