/***********************************************************************
 * 
 *  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 ]==================================================

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

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

// Debug Level
int   DebugLevel = 0;

//
// Initialization variables
//
static
bool  g_moduleInitialized = false;

//
// IPC Client Sub-system variables
// 
uint32_t atvsEndPointHandle;  // Authentication Token Validation Service endpoint handle

//++=======================================================================
CasaStatus SSCS_CALL
ValidateAuthToken(
   IN       const char  *pServiceName,
   IN       const char  *pTokenBuf,
   IN       const int   tokenBufLen,
   INOUT    PrincipalIf **ppPrincipalIf)
//
// Arguments:  
//    pServiceName -
//       Pointer to NULL terminated string that contains the
//       name of the service targeted by the token.
//               
//    pTokenBuf -
//       Pointer to buffer that will receive the authentication
//       token. The length of this buffer is specified by the
//       pTokenBufLen parameter. Note that the the authentication
//       token will be in the form of a NULL terminated string.
//
//    tokenBufLen -
//       Length of the data contained within the buffer pointed
//       at by pTokenBuf.
//   
//    ppPrincipalIf -
//       Pointer to variable that will receive a pointer to a principal
//       interface with information about the authenticated entity.
//       IMPORTANT NOTE: The caller is responsible for releasing the
//       interface after it is done with it to avoid a resource leak.
//   
// Returns:
//    Casa status.
//                           
// Description:
//    Validates authentication token.
//
// L2
//=======================================================================--
{
   CasaStatus        retStatus;
   char              *pDecodedTokenBuf;
   int               decodedTokenBufLen;
   PrincipalIf       *pPrincipalIf;

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

   // Validate input parameters
   if (pServiceName == NULL
       || pTokenBuf == NULL
       || tokenBufLen == 0
       || ppPrincipalIf == NULL)
   {
      DbgTrace(0, "-ValidateAuthToken- Invalid input parameter\n", 0);

      retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
                                  CASA_FACILITY_AUTHTOKEN,
                                  CASA_STATUS_INVALID_PARAMETER);
      goto exit;
   }

   // Make sure that the module has been initialized
   if (g_moduleInitialized == false)
   {
      // The module has not been initialized, synchronize access thought this section
      // to avoid having two threads performing initialization.
      AcquireModuleMutex;

      // Assume success
      retStatus = CASA_STATUS_SUCCESS;

      // Check again in case another thread pre-empted us.
      if (g_moduleInitialized == false)
      {
         // Initialize the ConfigIf complex
         retStatus = ConfigIfInit();
         if (CASA_SUCCESS(retStatus))
         {
            // Initialize the PrincipalIf complex
            retStatus = PrincipalIfInit();
            if (CASA_SUCCESS(retStatus))
            {
               // Initialize the IdenToken complex
               retStatus = IdenTokenInit();
               if (CASA_SUCCESS(retStatus))
               {
                  // Initialize the Client Ipc Subsystem
                  if (IpcClientInit("CASA_AuthTokenValidate",
                                    true,
                                    DebugLevel,
                                    false) == 0)
                  {
                     // Open endpoint for the Authentication Token Validation Service
                     if (IpcClientOpenInetRemoteEndPoint(5000,
                                                         0x7F000001,
                                                         0,
                                                         &atvsEndPointHandle) == 0)
                     {
                        // Success
                        g_moduleInitialized = true;
                     }
                     else
                     {
                        DbgTrace(0, "-ValidateAuthToken- Failed to open remote endpoint\n", 0);
                        IpcClientShutdown();
                        IdenTokenUninit();
                        PrincipalIfUninit();
                        ConfigIfUninit();
                     }
                  }
                  else
                  {
                     DbgTrace(0, "-ValidateAuthToken- Ipc subsystem initialization failed\n", 0);
                     IdenTokenUninit();
                     PrincipalIfUninit();
                     ConfigIfUninit();
                  }
               }
               else
               {
                  PrincipalIfUninit();
                  ConfigIfUninit();
               }
            }
            else
            {
               ConfigIfUninit();
            }
         }
      }

      // Stop synchronization
      ReleaseModuleMutex;

      // Exit if we failed
      if (g_moduleInitialized == false)
         goto exit;
   }

   // First decode the token string
   retStatus = DecodeData(pTokenBuf,
                          tokenBufLen,
                          (void**) &pDecodedTokenBuf,
                          &decodedTokenBufLen);
   if (CASA_SUCCESS(retStatus))
   {
      char *pIdenTokenData;
      int idenTokenDataLen;

      // Token was decoded successfully, now submit the authentication token to the
      // authentication token validation service.
      if (IpcClientSubmitReq(atvsEndPointHandle,
                             pDecodedTokenBuf,
                             decodedTokenBufLen,
                             &pIdenTokenData,
                             &idenTokenDataLen) == 0)
      {
         // The submit succeeded, make sure that we got some identity data back.
         if (pIdenTokenData)
         {
            if (idenTokenDataLen != 0)
            {
               IdenTokenProviderIf  *pIdenTokenProviderIf;

               // The authentication token was validated, now obtain
               // Identity Token Provider interface.
               retStatus = GetIdenTokenProviderInterface("CasaIdentityToken",    // tbd - Hard code until we enhance the protocol with the atvs to also return this information.
                                                         &pIdenTokenProviderIf);
               if (CASA_SUCCESS(retStatus))
               {
                  IdenTokenIf *pIdenTokenIf;

                  // Use the Identity Token Provider to get an Identity Token Interface instance
                  retStatus = pIdenTokenProviderIf->getIdentityTokenIf(pIdenTokenProviderIf,
                                                                       pIdenTokenData,
                                                                       idenTokenDataLen,
                                                                       &pIdenTokenIf);
                  if (CASA_SUCCESS(retStatus))
                  {
                     // Now create a principal interface instance with the identity information present in
                     // the identity token.
                     retStatus = GetPrincipalInterface(pIdenTokenIf, &pPrincipalIf);
                     if (CASA_SUCCESS(retStatus))
                     {
                        // Success, return the principal interface to the caller.
                        *ppPrincipalIf = pPrincipalIf;
                     }
                     else
                     {
                        DbgTrace(0, "-ValidateAuthToken- Failed to instantiate principal interface\n", 0);
                     }

                     // Release identity token interface
                     pIdenTokenIf->releaseReference(pIdenTokenIf);
                  }
                  else
                  {
                     DbgTrace(0, "-ValidateAuthToken- Failed to instantiate identity token\n", 0);
                  }

                  // Release identity token provider interface
                  pIdenTokenProviderIf->releaseReference(pIdenTokenProviderIf);
               }
               else
               {
                  DbgTrace(0, "-ValidateAuthToken- Failed to obtain identity token provider interface\n", 0);
               }
            }
            else
            {
               DbgTrace(0, "-ValidateAuthToken- ValidateAuthToken submit did not return identity token data\n", 0);
            }

            // Free the buffer containing the identity token data
            free(pIdenTokenData);
         }
         else
         {
            DbgTrace(0, "-ValidateAuthToken- ValidateAuthToken submit did not return identity token data buffer\n", 0);
         }
      }
      else
      {
         DbgTrace(1, "-ValidateAuthToken- ValidateAuthToken submit failed\n", 0);
      }


      // Free the decoded token buffer
      free(pDecodedTokenBuf);
   }
   else
   {
      DbgTrace(0, "-ValidateAuthToken- Token decode failure\n", 0);
   }

exit:

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

   return retStatus;
}


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