/*********************************************************************** * * 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_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; size_t elementDataProcessed; char *pStatusData; size_t statusDataLen; char *pLifetimeData; size_t lifetimeDataLen; GetAuthTokenResp *pGetAuthTokenResp; CasaStatus status; } GetAuthTokenRespParse, *PGetAuthTokenRespParse; //===[ Function prototypes ]=============================================== //===[ Global variables ]================================================== //++======================================================================= char* BuildGetAuthTokenMsg( IN const char *pServiceName, IN const char *pHostName, IN char *pSessionToken) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { char *pMsg = NULL; size_t bufferSize; DbgTrace(1, "-BuildGetAuthTokenMsg- Start\n", 0); /* * The format of the get authentication token request message * is as follows: * * * * service name * host name * session token data * * */ // 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 // crlf + 1 // < + strlen(HOST_ELEMENT_NAME) + 1 // > + strlen(pHostName) + 2 // crlf + 1 // < + strlen(SESSION_TOKEN_ELEMENT_NAME) + 1 // > + strlen(pSessionToken) + 2 // crlf + 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, "\r\n"); strcat(pMsg, "<"); strcat(pMsg, HOST_ELEMENT_NAME); strcat(pMsg, ">"); strcat(pMsg, pHostName); strcat(pMsg, "\r\n"); strcat(pMsg, "<"); strcat(pMsg, SESSION_TOKEN_ELEMENT_NAME); strcat(pMsg, ">"); strcat(pMsg, pSessionToken); strcat(pMsg, "\r\n"); strcat(pMsg, ""); } else { DbgTrace(0, "-BuildGetAuthTokenMsg- Buffer allocation error\n", 0); } DbgTrace(1, "-BuildGetAuthTokenMsg- End, pMsg = %0lX\n", (long) 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 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 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 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 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 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 size_t *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((size_t)(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 after clearing and freeing the original // buffer since it may contain sensitive information. memset(*ppElementData, 0, pGetAuthTokenRespParse->elementDataProcessed - len); *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 //=======================================================================-- { CasaStatus status; DbgTrace(2, "-GetAuthTokenRespCharDataHandler- Start\n", 0); // Just exit if being called to process white space if (*s == '\n' || *s == '\r' || *s == '\t' || *s == ' ') { 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: case AWAITING_STATUS_ELEMENT_END: // Consume the data status = ConsumeElementData(pGetAuthTokenRespParse, s, len, &pGetAuthTokenRespParse->pStatusData, &pGetAuthTokenRespParse->statusDataLen); if (CASA_SUCCESS(status)) { // Advanced to the next state pGetAuthTokenRespParse->state = AWAITING_STATUS_ELEMENT_END; } else { pGetAuthTokenRespParse->status = status; XML_StopParser(pGetAuthTokenRespParse->p, XML_FALSE); } break; case AWAITING_LIFETIME_DATA: case AWAITING_LIFETIME_ELEMENT_END: // Consume the data status = ConsumeElementData(pGetAuthTokenRespParse, s, len, &pGetAuthTokenRespParse->pLifetimeData, &pGetAuthTokenRespParse->lifetimeDataLen); if (CASA_SUCCESS(status)) { // Advanced to the next state pGetAuthTokenRespParse->state = AWAITING_LIFETIME_ELEMENT_END; } else { pGetAuthTokenRespParse->status = status; XML_StopParser(pGetAuthTokenRespParse->p, XML_FALSE); } break; case AWAITING_AUTH_TOKEN_DATA: case AWAITING_AUTH_TOKEN_ELEMENT_END: // Consume the data status = ConsumeElementData(pGetAuthTokenRespParse, s, len, &pGetAuthTokenRespParse->pGetAuthTokenResp->pToken, &pGetAuthTokenRespParse->pGetAuthTokenResp->tokenLen); if (CASA_SUCCESS(status)) { // Advanced to the next state pGetAuthTokenRespParse->state = AWAITING_AUTH_TOKEN_ELEMENT_END; } else { pGetAuthTokenRespParse->status = status; 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 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 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) { // Set the appropriate status in the GetAuthTokenResp based on the returned status data if (strncmp(HTTP_OK_STATUS_CODE, pGetAuthTokenRespParse->pStatusData, pGetAuthTokenRespParse->statusDataLen) == 0) { pGetAuthTokenRespParse->status = CASA_STATUS_SUCCESS; } else if (strncmp(HTTP_UNAUTHORIZED_STATUS_CODE, pGetAuthTokenRespParse->pStatusData, pGetAuthTokenRespParse->statusDataLen) == 0) { pGetAuthTokenRespParse->status = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_AUTHENTICATION_FAILURE); } else if (strncmp(HTTP_SERVER_ERROR_STATUS_CODE, pGetAuthTokenRespParse->pStatusData, pGetAuthTokenRespParse->statusDataLen) == 0) { pGetAuthTokenRespParse->status = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_SERVER_ERROR); } else { DbgTrace(0, "-GetAuthTokenRespEndElementHandler- Un-expected status\n", 0); pGetAuthTokenRespParse->status = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_UNSUCCESSFUL); } // 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 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) { // Convert the lifetime string to a numeric value pGetAuthTokenRespParse->pGetAuthTokenResp->tokenLifetime = dtoul(pGetAuthTokenRespParse->pLifetimeData, pGetAuthTokenRespParse->lifetimeDataLen); // Good, advance to the next state. pGetAuthTokenRespParse->state = AWAITING_AUTH_TOKEN_DATA; } else { DbgTrace(0, "-GetAuthTokenRespEndElementHandler- Un-expected 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 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 size_t 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: * * * * ok200 * lifetime valuesession token data * * * 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: * * * * status descriptionstatus code * * * Plase note that the protocol utilizes the status codes defined * in the HTTP 1.1 Specification. * */ // Verify that the response is not too large for the parser if (respLen > INT_MAX) { DbgTrace(0, "-CreateGetAuthTokenResp- Response too large\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_INFORMATIONAL, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_UNSUCCESSFUL); goto exit; } // 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, (XML_StartElementHandler) GetAuthTokenRespStartElementHandler, (XML_EndElementHandler) GetAuthTokenRespEndElementHandler); // Set the character data handler XML_SetCharacterDataHandler(p, (XML_CharacterDataHandler) GetAuthTokenRespCharDataHandler); // Set our user data XML_SetUserData(p, &getAuthTokenRespParse); // Parse the document if (XML_Parse(p, pRespMsg, (int) 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); // Free any buffers associated with the parse if (getAuthTokenRespParse.pStatusData) free(getAuthTokenRespParse.pStatusData); if (getAuthTokenRespParse.pLifetimeData) free(getAuthTokenRespParse.pLifetimeData); } 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); } exit: 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) { // Clear the memory associated with the token since it is // sensitive data. memset(pGetAuthTokenResp->pToken, 0, pGetAuthTokenResp->tokenLen); free(pGetAuthTokenResp->pToken); } free(pGetAuthTokenResp); DbgTrace(1, "-RelGetAuthTokenResp- End\n", 0); } //++======================================================================= //++======================================================================= //++=======================================================================