/*********************************************************************** * * 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 * ***********************************************************************/ //===[ Include files ]===================================================== #include "internal.h" //===[ Type definitions ]================================================== // // Parse states // #define AWAITING_ROOT_ELEMENT_START 0x0 #define AWAITING_ROOT_ELEMENT_END 0x1 #define AWAITING_SIGNATURE_DATA 0x2 #define AWAITING_SIGNATURE_ELEMENT_START 0x3 #define AWAITING_SIGNATURE_ELEMENT_END 0x4 #define AWAITING_LIFETIME_DATA 0x5 #define AWAITING_LIFETIME_ELEMENT_START 0x6 #define AWAITING_LIFETIME_ELEMENT_END 0x7 #define AWAITING_IDENT_TOKEN_ELEMENT_START 0x8 #define AWAITING_IDENT_TOKEN_ELEMENT_END 0x9 #define AWAITING_IDENT_TOKEN_DATA 0xA #define AWAITING_TYPE_ELEMENT_START 0xB #define AWAITING_TYPE_ELEMENT_END 0xC #define AWAITING_TYPE_DATA 0xD #define DONE_PARSING 0xE // // Authentication Token Parse Structure // typedef struct _AuthTokenParse { XML_Parser p; int state; int elementDataProcessed; AuthToken *pAuthToken; CasaStatus status; } AuthTokenParse, *PAuthTokenParse; //===[ Function prototypes ]=============================================== //===[ Global variables ]================================================== //++======================================================================= static void XMLCALL AuthTokenStartElementHandler( IN void *pUserData, IN const XML_Char *name, IN const XML_Char **atts) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { AuthTokenParse *pAuthTokenParse = (AuthTokenParse*) pUserData; DbgTrace(2, "-AuthTokenStartElementHandler- Start\n", 0); // Proceed based on the state switch (pAuthTokenParse->state) { case AWAITING_ROOT_ELEMENT_START: // In this state, we are only expecting the Authentication // Response Element. if (strcmp(name, AUTH_TOKEN_ELEMENT_NAME) == 0) { // Good, advance to the next state. pAuthTokenParse->state = AWAITING_SIGNATURE_ELEMENT_START; } else { DbgTrace(0, "-AuthTokenStartElementHandler- Un-expected start element\n", 0); XML_StopParser(pAuthTokenParse->p, XML_FALSE); } break; case AWAITING_SIGNATURE_ELEMENT_START: // In this state, we are only expecting the Signature Element. if (strcmp(name, SIGNATURE_ELEMENT_NAME) == 0) { // Good, advance to the next state. pAuthTokenParse->state = AWAITING_SIGNATURE_DATA; } else { DbgTrace(0, "-AuthTokenStartElementHandler- Un-expected start element\n", 0); XML_StopParser(pAuthTokenParse->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. pAuthTokenParse->state = AWAITING_LIFETIME_DATA; } else { DbgTrace(0, "-AuthTokenStartElementHandler- Un-expected start element\n", 0); XML_StopParser(pAuthTokenParse->p, XML_FALSE); } break; case AWAITING_IDENT_TOKEN_ELEMENT_START: // In this state, we are only expecting the Identity Token Element. if (strcmp(name, IDENTITY_TOKEN_ELEMENT_NAME) == 0) { // Good, advance to the next state. pAuthTokenParse->state = AWAITING_TYPE_ELEMENT_START; } else { DbgTrace(0, "-AuthTokenStartElementHandler- Un-expected start element\n", 0); XML_StopParser(pAuthTokenParse->p, XML_FALSE); } break; case AWAITING_TYPE_ELEMENT_START: // In this state, we are only expecting the Type Element. if (strcmp(name, TYPE_ELEMENT_NAME) == 0) { // Good, advance to the next state. pAuthTokenParse->state = AWAITING_TYPE_DATA; } else { DbgTrace(0, "-AuthTokenStartElementHandler- Un-expected start element\n", 0); XML_StopParser(pAuthTokenParse->p, XML_FALSE); } break; default: DbgTrace(0, "-AuthTokenStartElementHandler- Un-expected state = %d\n", pAuthTokenParse->state); XML_StopParser(pAuthTokenParse->p, XML_FALSE); break; } DbgTrace(2, "-AuthTokenStartElementHandler- End\n", 0); } //++======================================================================= static CasaStatus ConsumeElementData( IN AuthTokenParse *pAuthTokenParse, 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 pAuthTokenParse->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 = pAuthTokenParse->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(pAuthTokenParse->elementDataProcessed + len + 1); if (pNewBuf) { memset(pNewBuf, 0, pAuthTokenParse->elementDataProcessed + len + 1); memcpy(pNewBuf, *ppElementData, pAuthTokenParse->elementDataProcessed); memcpy(pNewBuf + pAuthTokenParse->elementDataProcessed, s, len); pAuthTokenParse->elementDataProcessed += len; // Swap the buffers free(*ppElementData); *ppElementData = pNewBuf; // Return the length of the element data buffer *pElementDataLen = pAuthTokenParse->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 AuthTokenCharDataHandler( IN void *pUserData, IN const XML_Char *s, IN int len) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { AuthTokenParse *pAuthTokenParse = (AuthTokenParse*) pUserData; DbgTrace(2, "-AuthTokenCharDataHandler- 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 (pAuthTokenParse->state) { case AWAITING_SIGNATURE_DATA: case AWAITING_SIGNATURE_ELEMENT_END: pAuthTokenParse->status = ConsumeElementData(pAuthTokenParse, s, len, &pAuthTokenParse->pAuthToken->pSignature, &pAuthTokenParse->pAuthToken->signatureLen); if (CASA_SUCCESS(pAuthTokenParse->status)) { // Advanced to the next state pAuthTokenParse->state = AWAITING_SIGNATURE_ELEMENT_END; } else { XML_StopParser(pAuthTokenParse->p, XML_FALSE); } break; case AWAITING_LIFETIME_DATA: case AWAITING_LIFETIME_ELEMENT_END: // Convert the lifetime string to a numeric value pAuthTokenParse->pAuthToken->tokenLifetime = dtoul((char*) s, len); // Advanced to the next state pAuthTokenParse->state = AWAITING_LIFETIME_ELEMENT_END; break; case AWAITING_TYPE_DATA: case AWAITING_TYPE_ELEMENT_END: pAuthTokenParse->status = ConsumeElementData(pAuthTokenParse, s, len, &pAuthTokenParse->pAuthToken->pIdenTokenType, &pAuthTokenParse->pAuthToken->idenTokenTypeLen); if (CASA_SUCCESS(pAuthTokenParse->status)) { // Advanced to the next state pAuthTokenParse->state = AWAITING_TYPE_ELEMENT_END; } else { XML_StopParser(pAuthTokenParse->p, XML_FALSE); } break; case AWAITING_IDENT_TOKEN_DATA: case AWAITING_IDENT_TOKEN_ELEMENT_END: pAuthTokenParse->status = ConsumeElementData(pAuthTokenParse, s, len, &pAuthTokenParse->pAuthToken->pIdenToken, &pAuthTokenParse->pAuthToken->idenTokenLen); if (CASA_SUCCESS(pAuthTokenParse->status)) { // Advanced to the next state pAuthTokenParse->state = AWAITING_IDENT_TOKEN_ELEMENT_END; } else { XML_StopParser(pAuthTokenParse->p, XML_FALSE); } break; default: DbgTrace(0, "-AuthTokenCharDataHandler- Un-expected state = %d\n", pAuthTokenParse->state); XML_StopParser(pAuthTokenParse->p, XML_FALSE); break; } exit: DbgTrace(2, "-AuthTokenCharDataHandler- End\n", 0); } //++======================================================================= static void XMLCALL AuthTokenEndElementHandler( IN void *pUserData, IN const XML_Char *name) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { AuthTokenParse *pAuthTokenParse = (AuthTokenParse*) pUserData; DbgTrace(2, "-AuthTokenEndElementHandler- Start\n", 0); // Proceed based on the state switch (pAuthTokenParse->state) { case AWAITING_ROOT_ELEMENT_END: // In this state, we are only expecting the Authentication // Token Element. if (strcmp(name, AUTH_TOKEN_ELEMENT_NAME) == 0) { // Done. pAuthTokenParse->state = DONE_PARSING; } else { DbgTrace(0, "-AuthTokenEndHandler- Un-expected end element\n", 0); XML_StopParser(pAuthTokenParse->p, XML_FALSE); } break; case AWAITING_SIGNATURE_ELEMENT_END: // In this state, we are only expecting the Signature Element. if (strcmp(name, SIGNATURE_ELEMENT_NAME) == 0) { // Good, advance to the next state. pAuthTokenParse->state = AWAITING_LIFETIME_ELEMENT_START; } else { DbgTrace(0, "-AuthTokenEndElementHandler- Un-expected end element\n", 0); XML_StopParser(pAuthTokenParse->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. pAuthTokenParse->state = AWAITING_IDENT_TOKEN_ELEMENT_START; } else { DbgTrace(0, "-AuthTokenEndElementHandler- Un-expected end element\n", 0); XML_StopParser(pAuthTokenParse->p, XML_FALSE); } break; case AWAITING_TYPE_ELEMENT_END: // In this state, we are only expecting the Type Element. if (strcmp(name, TYPE_ELEMENT_NAME) == 0) { // Good, advance to the next state. pAuthTokenParse->state = AWAITING_IDENT_TOKEN_DATA; } else { DbgTrace(0, "-AuthTokenEndElementHandler- Un-expected end element\n", 0); XML_StopParser(pAuthTokenParse->p, XML_FALSE); } break; case AWAITING_IDENT_TOKEN_ELEMENT_END: // In this state, we are only expecting the Identity Token Element. if (strcmp(name, IDENTITY_TOKEN_ELEMENT_NAME) == 0) { // Good, advance to the next state. pAuthTokenParse->state = AWAITING_ROOT_ELEMENT_END; } else { DbgTrace(0, "-AuthTokenEndElementHandler- Un-expected end element\n", 0); XML_StopParser(pAuthTokenParse->p, XML_FALSE); } break; default: DbgTrace(0, "-AuthTokenEndElementHandler- Un-expected state = %d\n", pAuthTokenParse->state); XML_StopParser(pAuthTokenParse->p, XML_FALSE); break; } DbgTrace(2, "-AuthTokenEndElementHandler- End\n", 0); } //++======================================================================= CasaStatus CreateAuthToken( IN char *pTokenBuf, IN int tokenBufLen, INOUT AuthToken **ppAuthToken) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { CasaStatus retStatus = CASA_STATUS_SUCCESS; AuthTokenParse authTokenParse = {0}; AuthToken *pAuthToken; DbgTrace(1, "-CreateAuthToken- Start\n", 0); /* * Authentication tokens have the following format: * * * * signature value * lifetime value * identity token typeidentity token data * * */ // Allocate AuthToken object pAuthToken = malloc(sizeof(*pAuthToken)); if (pAuthToken) { XML_Parser p; // Initialize the AuthToken object and set it in the // authentication response parse object. memset(pAuthToken, 0, sizeof(*pAuthToken)); authTokenParse.pAuthToken = pAuthToken; // Create parser p = XML_ParserCreate(NULL); if (p) { // Keep track of the parser in our parse object authTokenParse.p = p; // Initialize the status within the parse object authTokenParse.status = CASA_STATUS_SUCCESS; // Set the start and end element handlers XML_SetElementHandler(p, AuthTokenStartElementHandler, AuthTokenEndElementHandler); // Set the character data handler XML_SetCharacterDataHandler(p, AuthTokenCharDataHandler); // Set our user data XML_SetUserData(p, &authTokenParse); // Parse the document if (XML_Parse(p, pTokenBuf, tokenBufLen, 1) == XML_STATUS_OK) { // Verify that the parse operation completed successfully if (authTokenParse.state == DONE_PARSING) { // The parse operation succeded. retStatus = CASA_STATUS_SUCCESS; } else { DbgTrace(0, "-CreateAuthToken- Parse operation did not complete\n", 0); // Check if a status has been recorded if (authTokenParse.status != CASA_STATUS_SUCCESS) { retStatus = authTokenParse.status; } else { retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_PROTOCOL_ERROR); } } } else { DbgTrace(0, "-CreateAuthToken- 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, "-CreateAuthToken- 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)) { *ppAuthToken = pAuthToken; } else { free(pAuthToken); } } else { DbgTrace(0, "-CreateAuthToken- Memory allocation error\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_INSUFFICIENT_RESOURCES); } DbgTrace(1, "-CreateAuthToken- End, retStatus = %08X\n", retStatus); return retStatus; } //++======================================================================= void RelAuthToken( IN AuthToken *pAuthToken) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { DbgTrace(1, "-RelAuthToken- Start\n", 0); // Free the resources associated with the object if (pAuthToken->pSignature) free(pAuthToken->pSignature); if (pAuthToken->pIdenTokenType) free(pAuthToken->pIdenTokenType); if (pAuthToken->pIdenToken) free(pAuthToken->pIdenToken); free(pAuthToken); DbgTrace(1, "-RelAuthToken- End\n", 0); } //++======================================================================= CasaStatus CheckAuthToken( IN AuthToken *pAuthToken, IN const char *pServiceName) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L0 //=======================================================================-- { CasaStatus retStatus = CASA_STATUS_SUCCESS; DbgTrace(1, "-CheckuthToken- Start\n", 0); // tbd DbgTrace(1, "-CheckAuthToken- End, retStatus = %08X\n", retStatus); return retStatus; }