CASA/auth_token/client/gettokenmsg.c
2006-04-28 18:58:25 +00:00

795 lines
26 KiB
C

/***********************************************************************
*
* 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 ]==================================================
//
// Parse states
//
#define AWAITING_ROOT_ELEMENT_START 0x0
#define AWAITING_ROOT_ELEMENT_END 0x1
#define AWAITING_STATUS_ELEMENT_START 0x2
#define AWAITING_STATUS_ELEMENT_END 0x3
#define AWAITING_STATUS_DATA 0x4
#define AWAITING_DESCRIPTION_ELEMENT_START 0x5
#define AWAITING_DESCRIPTION_ELEMENT_END 0x6
#define AWAITING_DESCRIPTION_DATA 0x7
#define AWAITING_LIFETIME_DATA 0x8
#define AWAITING_LIFETIME_ELEMENT_START 0x9
#define AWAITING_LIFETIME_ELEMENT_END 0xA
#define AWAITING_AUTH_TOKEN_ELEMENT_START 0xB
#define AWAITING_AUTH_TOKEN_ELEMENT_END 0xC
#define AWAITING_AUTH_TOKEN_DATA 0xD
#define DONE_PARSING 0xE
//
// Get Authentication Token Response Parse Structure
//
typedef struct _GetAuthTokenRespParse
{
XML_Parser p;
int state;
int elementDataProcessed;
GetAuthTokenResp *pGetAuthTokenResp;
CasaStatus status;
} GetAuthTokenRespParse, *PGetAuthTokenRespParse;
//===[ Function prototypes ]===============================================
//===[ Global variables ]==================================================
//++=======================================================================
char*
BuildGetAuthTokenMsg(
IN char *pServiceName,
IN char *pHostName,
IN char *pSessionToken)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
char *pMsg = NULL;
int bufferSize;
DbgTrace(1, "-BuildGetAuthTokenMsg- Start\n", 0);
/*
* The format of the get authentication token request message
* is as follows:
*
* <?xml version="1.0" encoding="ISO-8859-1"?>
* <get_auth_token_req>
* <service>service name</service>
* <host>host name</host>
* <session_token>session token data</session_token>
* </get_auth_token_req>
*
*/
// Determine the buffer size necessary to hold the msg
bufferSize = strlen(XML_DECLARATION)
+ 2 // crlf
+ 1 // <
+ strlen(GET_AUTH_TOKEN_REQUEST_ELEMENT_NAME)
+ 3 // >crlf
+ 1 // <
+ strlen(SERVICE_ELEMENT_NAME)
+ 1 // >
+ strlen(pServiceName)
+ 2 // </
+ strlen(SERVICE_ELEMENT_NAME)
+ 3 // >crlf
+ 1 // <
+ strlen(HOST_ELEMENT_NAME)
+ 1 // >
+ strlen(pHostName)
+ 2 // </
+ strlen(HOST_ELEMENT_NAME)
+ 3 // >crlf
+ 1 // <
+ strlen(SESSION_TOKEN_ELEMENT_NAME)
+ 1 // >
+ strlen(pSessionToken)
+ 2 // </
+ strlen(SESSION_TOKEN_ELEMENT_NAME)
+ 3 // >crlf
+ 2 // </
+ strlen(GET_AUTH_TOKEN_REQUEST_ELEMENT_NAME)
+ 2; // >null
// Allocate the msg buffer
pMsg = (char*) malloc(bufferSize);
if (pMsg)
{
// Now build the message
memset(pMsg, 0, bufferSize);
strcat(pMsg, XML_DECLARATION);
strcat(pMsg, "\r\n");
strcat(pMsg, "<");
strcat(pMsg, GET_AUTH_TOKEN_REQUEST_ELEMENT_NAME);
strcat(pMsg, ">\r\n");
strcat(pMsg, "<");
strcat(pMsg, SERVICE_ELEMENT_NAME);
strcat(pMsg, ">");
strcat(pMsg, pServiceName);
strcat(pMsg, "</");
strcat(pMsg, SERVICE_ELEMENT_NAME);
strcat(pMsg, ">\r\n");
strcat(pMsg, "<");
strcat(pMsg, HOST_ELEMENT_NAME);
strcat(pMsg, ">");
strcat(pMsg, pHostName);
strcat(pMsg, "</");
strcat(pMsg, HOST_ELEMENT_NAME);
strcat(pMsg, ">\r\n");
strcat(pMsg, "<");
strcat(pMsg, SESSION_TOKEN_ELEMENT_NAME);
strcat(pMsg, ">");
strcat(pMsg, pSessionToken);
strcat(pMsg, "</");
strcat(pMsg, SESSION_TOKEN_ELEMENT_NAME);
strcat(pMsg, ">\r\n");
strcat(pMsg, "</");
strcat(pMsg, GET_AUTH_TOKEN_REQUEST_ELEMENT_NAME);
strcat(pMsg, ">");
}
else
{
DbgTrace(0, "-BuildGetAuthTokenMsg- Buffer allocation error\n", 0);
}
DbgTrace(1, "-BuildGetAuthTokenMsg- End, pMsg = %08X\n", pMsg);
return pMsg;
}
//++=======================================================================
static
void XMLCALL
GetAuthTokenRespStartElementHandler(
IN GetAuthTokenRespParse *pGetAuthTokenRespParse,
IN const XML_Char *name,
IN const XML_Char **atts)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
DbgTrace(2, "-GetAuthTokenRespStartElementHandler- Start\n", 0);
// Proceed based on the state
switch (pGetAuthTokenRespParse->state)
{
case AWAITING_ROOT_ELEMENT_START:
// In this state, we are only expecting the Get Authentication
// Token Response Element.
if (strcmp(name, GET_AUTH_TOKEN_RESPONSE_ELEMENT_NAME) == 0)
{
// Good, advance to the next state.
pGetAuthTokenRespParse->state = AWAITING_STATUS_ELEMENT_START;
}
else
{
DbgTrace(0, "-GetAuthTokenRespStartElementHandler- Un-expected start element\n", 0);
XML_StopParser(pGetAuthTokenRespParse->p, XML_FALSE);
}
break;
case AWAITING_STATUS_ELEMENT_START:
// In this state, we are only expecting the Status Element.
if (strcmp(name, STATUS_ELEMENT_NAME) == 0)
{
// Good, advance to the next state.
pGetAuthTokenRespParse->state = AWAITING_DESCRIPTION_ELEMENT_START;
}
else
{
DbgTrace(0, "-GetAuthTokenRespStartElementHandler- Un-expected start element\n", 0);
XML_StopParser(pGetAuthTokenRespParse->p, XML_FALSE);
}
break;
case AWAITING_DESCRIPTION_ELEMENT_START:
// In this state, we are only expecting the Description Element.
if (strcmp(name, DESCRIPTION_ELEMENT_NAME) == 0)
{
// Good, advance to the next state.
pGetAuthTokenRespParse->state = AWAITING_DESCRIPTION_DATA;
}
else
{
DbgTrace(0, "-GetAuthTokenRespStartElementHandler- Un-expected start element\n", 0);
XML_StopParser(pGetAuthTokenRespParse->p, XML_FALSE);
}
break;
case AWAITING_AUTH_TOKEN_ELEMENT_START:
// In this state, we are only expecting the Authentication Token Element.
if (strcmp(name, AUTH_TOKEN_ELEMENT_NAME) == 0)
{
// Good, advance to the next state.
pGetAuthTokenRespParse->state = AWAITING_LIFETIME_ELEMENT_START;
}
else
{
DbgTrace(0, "-GetAuthTokenRespStartElementHandler- Un-expected start element\n", 0);
XML_StopParser(pGetAuthTokenRespParse->p, XML_FALSE);
}
break;
case AWAITING_LIFETIME_ELEMENT_START:
// In this state, we are only expecting the Lifetime Element.
if (strcmp(name, LIFETIME_ELEMENT_NAME) == 0)
{
// Good, advance to the next state.
pGetAuthTokenRespParse->state = AWAITING_LIFETIME_DATA;
}
else
{
DbgTrace(0, "-GetAuthTokenRespStartElementHandler- Un-expected start element\n", 0);
XML_StopParser(pGetAuthTokenRespParse->p, XML_FALSE);
}
break;
default:
DbgTrace(0, "-GetAuthTokenRespStartElementHandler- Un-expected state = %d\n", pGetAuthTokenRespParse->state);
XML_StopParser(pGetAuthTokenRespParse->p, XML_FALSE);
break;
}
DbgTrace(2, "-GetAuthTokenRespStartElementHandler- End\n", 0);
}
//++=======================================================================
static
CasaStatus
ConsumeElementData(
IN GetAuthTokenRespParse *pGetAuthTokenRespParse,
IN const XML_Char *s,
IN int len,
INOUT char **ppElementData,
INOUT int *pElementDataLen)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
CasaStatus retStatus = CASA_STATUS_SUCCESS;
DbgTrace(3, "-ConsumeElementData- Start\n", 0);
// Proceed based on whether or not we have already consumed data
// for this element.
if (*ppElementData == NULL)
{
// We have not yet consumed data for this element
pGetAuthTokenRespParse->elementDataProcessed = len;
// Allocate a buffer to hold this element data (null terminated).
*ppElementData = (char*) malloc(len + 1);
if (*ppElementData)
{
memset(*ppElementData, 0, len + 1);
memcpy(*ppElementData, s, len);
// Return the length of the element data buffer
*pElementDataLen = pGetAuthTokenRespParse->elementDataProcessed + 1;
}
else
{
DbgTrace(0, "-ConsumeElementData- Buffer allocation failure\n", 0);
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_INSUFFICIENT_RESOURCES);
}
}
else
{
char *pNewBuf;
// We have already received token data, append this data to it.
pNewBuf = (char*) malloc(pGetAuthTokenRespParse->elementDataProcessed + len + 1);
if (pNewBuf)
{
memset(pNewBuf,
0,
pGetAuthTokenRespParse->elementDataProcessed + len + 1);
memcpy(pNewBuf,
*ppElementData,
pGetAuthTokenRespParse->elementDataProcessed);
memcpy(pNewBuf + pGetAuthTokenRespParse->elementDataProcessed, s, len);
pGetAuthTokenRespParse->elementDataProcessed += len;
// Swap the buffers
free(*ppElementData);
*ppElementData = pNewBuf;
// Return the length of the element data buffer
*pElementDataLen = pGetAuthTokenRespParse->elementDataProcessed + 1;
}
else
{
DbgTrace(0, "-ConsumeElementData- Buffer allocation failure\n", 0);
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_INSUFFICIENT_RESOURCES);
}
}
DbgTrace(3, "-ConsumeElementData- End, retStatus = %08X\n", retStatus);
return retStatus;
}
//++=======================================================================
static
void XMLCALL
GetAuthTokenRespCharDataHandler(
IN GetAuthTokenRespParse *pGetAuthTokenRespParse,
IN const XML_Char *s,
IN int len)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
DbgTrace(2, "-GetAuthTokenRespCharDataHandler- Start\n", 0);
// Just exit if being called to process LF and CR characters
if (len == 1
&& ((*s == '\n') || (*s == '\r')))
{
goto exit;
}
// Proceed based on the state
switch (pGetAuthTokenRespParse->state)
{
case AWAITING_DESCRIPTION_DATA:
case AWAITING_DESCRIPTION_ELEMENT_END:
// Ignore the status description data for now.
// tbd
// Advanced to the next state
pGetAuthTokenRespParse->state = AWAITING_DESCRIPTION_ELEMENT_END;
break;
case AWAITING_STATUS_DATA:
// Set the appropriate status in the AuthenticationResp based on the
// returned status.
if (strncmp(HTTP_OK_STATUS_CODE, s, len) == 0)
{
pGetAuthTokenRespParse->status = CASA_STATUS_SUCCESS;
}
else if (strncmp(HTTP_UNAUTHORIZED_STATUS_CODE, s, len) == 0)
{
pGetAuthTokenRespParse->status = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_AUTHENTICATION_FAILURE);
}
else if (strncmp(HTTP_SERVER_ERROR_STATUS_CODE, s, len) == 0)
{
pGetAuthTokenRespParse->status = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_SERVER_ERROR);
}
else
{
DbgTrace(0, "-GetAuthTokenRespCharDataHandler- Un-expected status\n", 0);
pGetAuthTokenRespParse->status = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_UNSUCCESSFUL);
}
// Advanced to the next state
pGetAuthTokenRespParse->state = AWAITING_STATUS_ELEMENT_END;
break;
case AWAITING_LIFETIME_DATA:
// Convert the lifetime string to a numeric value
pGetAuthTokenRespParse->pGetAuthTokenResp->tokenLifetime = dtoul(s, len);
// Advanced to the next state
pGetAuthTokenRespParse->state = AWAITING_LIFETIME_ELEMENT_END;
break;
case AWAITING_AUTH_TOKEN_DATA:
case AWAITING_AUTH_TOKEN_ELEMENT_END:
// Consume the data
pGetAuthTokenRespParse->status = ConsumeElementData(pGetAuthTokenRespParse,
s,
len,
&pGetAuthTokenRespParse->pGetAuthTokenResp->pToken,
&pGetAuthTokenRespParse->pGetAuthTokenResp->tokenLen);
if (CASA_SUCCESS(pGetAuthTokenRespParse->status))
{
// Advanced to the next state
pGetAuthTokenRespParse->state = AWAITING_AUTH_TOKEN_ELEMENT_END;
}
else
{
XML_StopParser(pGetAuthTokenRespParse->p, XML_FALSE);
}
break;
default:
DbgTrace(0, "-GetAuthTokenRespCharDataHandler- Un-expected state = %d\n", pGetAuthTokenRespParse->state);
XML_StopParser(pGetAuthTokenRespParse->p, XML_FALSE);
break;
}
exit:
DbgTrace(2, "-GetAuthTokenRespCharDataHandler- End\n", 0);
}
//++=======================================================================
static
void XMLCALL
GetAuthTokenRespEndElementHandler(
IN GetAuthTokenRespParse *pGetAuthTokenRespParse,
IN const XML_Char *name)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
DbgTrace(2, "-GetAuthTokenRespEndElementHandler- Start\n", 0);
// Proceed based on the state
switch (pGetAuthTokenRespParse->state)
{
case AWAITING_ROOT_ELEMENT_END:
// In this state, we are only expecting the Get Authentication
// Token Response Element.
if (strcmp(name, GET_AUTH_TOKEN_RESPONSE_ELEMENT_NAME) == 0)
{
// Done.
pGetAuthTokenRespParse->state = DONE_PARSING;
}
else
{
DbgTrace(0, "-GetAuthTokenRespEndHandler- Un-expected end element\n", 0);
XML_StopParser(pGetAuthTokenRespParse->p, XML_FALSE);
}
break;
case AWAITING_DESCRIPTION_ELEMENT_END:
// In this state, we are only expecting the Description Element.
if (strcmp(name, DESCRIPTION_ELEMENT_NAME) == 0)
{
// Good, advance to the next state.
pGetAuthTokenRespParse->state = AWAITING_STATUS_DATA;
}
else
{
DbgTrace(0, "-GetAuthTokenRespEndElementHandler- Un-expected end element\n", 0);
XML_StopParser(pGetAuthTokenRespParse->p, XML_FALSE);
}
break;
case AWAITING_STATUS_ELEMENT_END:
// In this state, we are only expecting the Status Element.
if (strcmp(name, STATUS_ELEMENT_NAME) == 0)
{
// Good, advance to the next state based on the status code.
if (CASA_SUCCESS(pGetAuthTokenRespParse->status))
{
// The request completed successfully
pGetAuthTokenRespParse->state = AWAITING_AUTH_TOKEN_ELEMENT_START;
}
else
{
pGetAuthTokenRespParse->state = AWAITING_ROOT_ELEMENT_END;
}
}
else
{
DbgTrace(0, "-GetAuthTokenRespEndElementHandler- Un-expected start element\n", 0);
XML_StopParser(pGetAuthTokenRespParse->p, XML_FALSE);
}
break;
case AWAITING_LIFETIME_ELEMENT_END:
// In this state, we are only expecting the Lifetime Element.
if (strcmp(name, LIFETIME_ELEMENT_NAME) == 0)
{
// Good, advance to the next state.
pGetAuthTokenRespParse->state = AWAITING_AUTH_TOKEN_DATA;
}
else
{
DbgTrace(0, "-GetAuthTokenRespEndElementHandler- Un-expected start element\n", 0);
XML_StopParser(pGetAuthTokenRespParse->p, XML_FALSE);
}
break;
case AWAITING_AUTH_TOKEN_ELEMENT_END:
// In this state, we are only expecting the Authentication Token Element.
if (strcmp(name, AUTH_TOKEN_ELEMENT_NAME) == 0)
{
// Good, advance to the next state.
pGetAuthTokenRespParse->state = AWAITING_ROOT_ELEMENT_END;
}
else
{
DbgTrace(0, "-GetAuthTokenRespEndElementHandler- Un-expected start element\n", 0);
XML_StopParser(pGetAuthTokenRespParse->p, XML_FALSE);
}
break;
default:
DbgTrace(0, "-GetAuthTokenRespEndElementHandler- Un-expected state = %d\n", pGetAuthTokenRespParse->state);
XML_StopParser(pGetAuthTokenRespParse->p, XML_FALSE);
break;
}
DbgTrace(2, "-GetAuthTokenRespEndElementHandler- End\n", 0);
}
//++=======================================================================
CasaStatus
CreateGetAuthTokenResp(
IN char *pRespMsg,
IN int respLen,
INOUT GetAuthTokenResp **ppGetAuthTokenResp)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
CasaStatus retStatus = CASA_STATUS_SUCCESS;
GetAuthTokenRespParse getAuthTokenRespParse = {0};
GetAuthTokenResp *pGetAuthTokenResp;
DbgTrace(1, "-CreateGetAuthTokenResp- Start\n", 0);
/*
* When a get authentication token request is processed successfully, the
* server replies to the client with a message with the following format:
*
* <?xml version="1.0" encoding="ISO-8859-1"?>
* <get_auth_token_resp>
* <status><description>ok</description>200</status>
* <auth_token><lifetime>lifetime value</lifetime>session token data</auth_token>
* </get_auth_token_resp>
*
* When a get authentication token request fails to be successfully processed,
* the server responds with an error and an error description string. The message
* format of an unsuccessful reply is as follows:
*
* <?xml version="1.0" encoding="ISO-8859-1"?>
* <get_auth_token_resp>
* <status><description>status description</description>status code</status>
* </get_auth_token_resp>
*
* Plase note that the protocol utilizes the status codes defined
* in the HTTP 1.1 Specification.
*
*/
// Allocate GetAuthTokenResp object
pGetAuthTokenResp = malloc(sizeof(*pGetAuthTokenResp));
if (pGetAuthTokenResp)
{
XML_Parser p;
// Initialize the GetAuthTokenResp object and set it in the
// parse oject.
memset(pGetAuthTokenResp, 0, sizeof(*pGetAuthTokenResp));
getAuthTokenRespParse.pGetAuthTokenResp = pGetAuthTokenResp;
// Create parser
p = XML_ParserCreate(NULL);
if (p)
{
// Keep track of the parser in our parse object
getAuthTokenRespParse.p = p;
// Initialize the status within the parse object
getAuthTokenRespParse.status = CASA_STATUS_SUCCESS;
// Set the start and end element handlers
XML_SetElementHandler(p,
GetAuthTokenRespStartElementHandler,
GetAuthTokenRespEndElementHandler);
// Set the character data handler
XML_SetCharacterDataHandler(p, GetAuthTokenRespCharDataHandler);
// Set our user data
XML_SetUserData(p, &getAuthTokenRespParse);
// Parse the document
if (XML_Parse(p, pRespMsg, respLen, 1) == XML_STATUS_OK)
{
// Verify that the parse operation completed successfully
if (getAuthTokenRespParse.state == DONE_PARSING)
{
// The parse operation succeded, obtain the status returned
// by the server.
retStatus = getAuthTokenRespParse.status;
}
else
{
DbgTrace(0, "-CreateGetAuthTokenResp- Parse operation did not complete\n", 0);
// Check if a status has been recorded
if (getAuthTokenRespParse.status != CASA_STATUS_SUCCESS)
{
retStatus = getAuthTokenRespParse.status;
}
else
{
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_PROTOCOL_ERROR);
}
}
}
else
{
DbgTrace(0, "-CreateGetAuthTokenResp- Parse error %d\n", XML_GetErrorCode(p));
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_PROTOCOL_ERROR);
}
// Free the parser
XML_ParserFree(p);
}
else
{
DbgTrace(0, "-CreateGetAuthTokenResp- Parser creation error\n", 0);
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_INSUFFICIENT_RESOURCES);
}
// Return the AuthenticationResp object to the caller if necessary
if (CASA_SUCCESS(retStatus))
{
*ppGetAuthTokenResp = pGetAuthTokenResp;
}
else
{
free(pGetAuthTokenResp);
}
}
else
{
DbgTrace(0, "-CreateGetAuthTokenResp- Memory allocation error\n", 0);
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_INSUFFICIENT_RESOURCES);
}
DbgTrace(1, "-CreateGetAuthTokenResp- End, retStatus = %08X\n", retStatus);
return retStatus;
}
//++=======================================================================
void
RelGetAuthTokenResp(
IN GetAuthTokenResp *pGetAuthTokenResp)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
DbgTrace(1, "-RelGetAuthTokenResp- Start\n", 0);
// Free the resources associated with the object
if (pGetAuthTokenResp->pToken)
free(pGetAuthTokenResp->pToken);
free(pGetAuthTokenResp);
DbgTrace(1, "-RelGetAuthTokenResp- End\n", 0);
}
//++=======================================================================
//++=======================================================================
//++=======================================================================