/*********************************************************************** * * 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_AUTH_TOKEN_ELEMENT_START 0x8 #define AWAITING_AUTH_TOKEN_ELEMENT_END 0x9 #define AWAITING_AUTH_TOKEN_DATA 0xA #define AWAITING_AUTH_POLICY_ELEMENT_START 0xB #define AWAITING_AUTH_POLICY_ELEMENT_END 0xC #define AWAITING_AUTH_POLICY_DATA 0xD #define DONE_PARSING 0xE // // Get Authentication Policy Response Parse Structure // typedef struct _GetAuthPolicyRespParse { XML_Parser p; int state; size_t elementDataProcessed; char *pStatusData; size_t statusDataLen; GetAuthPolicyResp *pGetAuthPolicyResp; CasaStatus status; } GetAuthPolicyRespParse, *PGetAuthPolicyRespParse; //===[ Function prototypes ]=============================================== //===[ Global variables ]================================================== //++======================================================================= char* BuildGetAuthPolicyMsg( IN const char *pServiceName, IN const char *pHostName) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { char *pMsg = NULL; size_t bufferSize; DbgTrace(1, "-BuildGetAuthPolicyMsg- Start\n", 0); /* * The format of the get authentication policy request message is as follows: * * * * service name<\service> * host name * * */ // Determine the buffer size necessary to hold the msg bufferSize = strlen(XML_DECLARATION) + 2 // crlf + 1 // < + strlen(GET_AUTH_POLICY_REQUEST_ELEMENT_NAME) + 3 // >crlf + 1 // < + strlen(SERVICE_ELEMENT_NAME) + 1 // > + strlen(pServiceName) + 2 // crlf + 2 // + strlen(pHostName) + 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_POLICY_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, ""); } else { DbgTrace(0, "-BuildGetAuthPolicyMsg- Buffer allocation error\n", 0); } DbgTrace(1, "-BuildGetAuthPolicyMsg- End, pMsg = %0lX\n", (long) pMsg); return pMsg; } //++======================================================================= static void XMLCALL GetAuthPolicyRespStartElementHandler( IN GetAuthPolicyRespParse *pGetAuthPolicyRespParse, IN const XML_Char *name, IN const XML_Char **atts) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { DbgTrace(2, "-GetAuthPolicyRespStartElementHandler- Start\n", 0); // Proceed based on the state switch (pGetAuthPolicyRespParse->state) { case AWAITING_ROOT_ELEMENT_START: // In this state, we are only expecting the Get Authentication // Policy Response Element. if (strcmp(name, GET_AUTH_POLICY_RESPONSE_ELEMENT_NAME) == 0) { // Good, advance to the next state. pGetAuthPolicyRespParse->state = AWAITING_STATUS_ELEMENT_START; } else { DbgTrace(0, "-GetAuthPolicyRespStartElementHandler- Un-expected element\n", 0); XML_StopParser(pGetAuthPolicyRespParse->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. pGetAuthPolicyRespParse->state = AWAITING_DESCRIPTION_ELEMENT_START; } else { DbgTrace(0, "-GetAuthPolicyRespStartElementHandler- Un-expected element\n", 0); XML_StopParser(pGetAuthPolicyRespParse->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. pGetAuthPolicyRespParse->state = AWAITING_DESCRIPTION_DATA; } else { DbgTrace(0, "-GetAuthPolicyRespStartElementHandler- Un-expected element\n", 0); XML_StopParser(pGetAuthPolicyRespParse->p, XML_FALSE); } break; case AWAITING_AUTH_POLICY_ELEMENT_START: // In this state, we are only expecting the Authentication Policy Element. if (strcmp(name, AUTH_POLICY_ELEMENT_NAME) == 0) { // Good, advance to the next state. pGetAuthPolicyRespParse->state = AWAITING_AUTH_POLICY_DATA; } else { DbgTrace(0, "-GetAuthPolicyRespStartElementHandler- Un-expected element\n", 0); XML_StopParser(pGetAuthPolicyRespParse->p, XML_FALSE); } break; default: DbgTrace(0, "-GetAuthPolicyRespStartElementHandler- Un-expected state = %d\n", pGetAuthPolicyRespParse->state); XML_StopParser(pGetAuthPolicyRespParse->p, XML_FALSE); break; } DbgTrace(2, "-GetAuthPolicyRespStartElementHandler- End\n", 0); } //++======================================================================= static CasaStatus ConsumeElementData( IN GetAuthPolicyRespParse *pGetAuthPolicyRespParse, 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 pGetAuthPolicyRespParse->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 = pGetAuthPolicyRespParse->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)(pGetAuthPolicyRespParse->elementDataProcessed + len + 1)); if (pNewBuf) { memset(pNewBuf, 0, pGetAuthPolicyRespParse->elementDataProcessed + len + 1); memcpy(pNewBuf, *ppElementData, pGetAuthPolicyRespParse->elementDataProcessed); memcpy(pNewBuf + pGetAuthPolicyRespParse->elementDataProcessed, s, len); pGetAuthPolicyRespParse->elementDataProcessed += len; // Swap the buffers free(*ppElementData); *ppElementData = pNewBuf; // Return the length of the element data buffer *pElementDataLen = pGetAuthPolicyRespParse->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 GetAuthPolicyRespCharDataHandler( IN GetAuthPolicyRespParse *pGetAuthPolicyRespParse, IN const XML_Char *s, IN int len) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { CasaStatus status; DbgTrace(2, "-GetAuthPolicyRespCharDataHandler- 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 (pGetAuthPolicyRespParse->state) { case AWAITING_DESCRIPTION_DATA: case AWAITING_DESCRIPTION_ELEMENT_END: // Ignore the status description data for now. // tbd // Advanced to the next state pGetAuthPolicyRespParse->state = AWAITING_DESCRIPTION_ELEMENT_END; break; case AWAITING_STATUS_DATA: case AWAITING_STATUS_ELEMENT_END: // Consume the data status = ConsumeElementData(pGetAuthPolicyRespParse, s, len, &pGetAuthPolicyRespParse->pStatusData, &pGetAuthPolicyRespParse->statusDataLen); if (CASA_SUCCESS(status)) { // Advanced to the next state pGetAuthPolicyRespParse->state = AWAITING_STATUS_ELEMENT_END; } else { pGetAuthPolicyRespParse->status = status; XML_StopParser(pGetAuthPolicyRespParse->p, XML_FALSE); } break; case AWAITING_AUTH_POLICY_DATA: case AWAITING_AUTH_POLICY_ELEMENT_END: status = ConsumeElementData(pGetAuthPolicyRespParse, s, len, &pGetAuthPolicyRespParse->pGetAuthPolicyResp->pPolicy, &pGetAuthPolicyRespParse->pGetAuthPolicyResp->policyLen); if (CASA_SUCCESS(status)) { // Advanced to the next state pGetAuthPolicyRespParse->state = AWAITING_AUTH_POLICY_ELEMENT_END; } else { pGetAuthPolicyRespParse->status = status; XML_StopParser(pGetAuthPolicyRespParse->p, XML_FALSE); } break; default: DbgTrace(0, "-GetAuthPolicyRespCharDataHandler- Un-expected state = %d\n", pGetAuthPolicyRespParse->state); XML_StopParser(pGetAuthPolicyRespParse->p, XML_FALSE); break; } exit: DbgTrace(2, "-GetAuthPolicyRespCharDataHandler- End\n", 0); } //++======================================================================= static void XMLCALL GetAuthPolicyRespEndElementHandler( IN GetAuthPolicyRespParse *pGetAuthPolicyRespParse, IN const XML_Char *name) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { DbgTrace(2, "-GetAuthPolicyRespEndElementHandler- Start\n", 0); // Proceed based on the state switch (pGetAuthPolicyRespParse->state) { case AWAITING_ROOT_ELEMENT_END: // In this state, we are only expecting the Get Authentication // Policy Response Element. if (strcmp(name, GET_AUTH_POLICY_RESPONSE_ELEMENT_NAME) == 0) { // Done. pGetAuthPolicyRespParse->state = DONE_PARSING; } else { DbgTrace(0, "-GetAuthPolicyRespEndHandler- Un-expected element\n", 0); XML_StopParser(pGetAuthPolicyRespParse->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. pGetAuthPolicyRespParse->state = AWAITING_STATUS_DATA; } else { DbgTrace(0, "-GetAuthPolicyRespEndElementHandler- Un-expected element\n", 0); XML_StopParser(pGetAuthPolicyRespParse->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 GetAuthPolicyResp based on the returned status data if (strncmp(HTTP_OK_STATUS_CODE, pGetAuthPolicyRespParse->pStatusData, pGetAuthPolicyRespParse->statusDataLen) == 0) { pGetAuthPolicyRespParse->status = CASA_STATUS_SUCCESS; } else if (strncmp(HTTP_UNAUTHORIZED_STATUS_CODE, pGetAuthPolicyRespParse->pStatusData, pGetAuthPolicyRespParse->statusDataLen) == 0) { pGetAuthPolicyRespParse->status = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_AUTHENTICATION_FAILURE); } else if (strncmp(HTTP_NOT_FOUND_STATUS_CODE, pGetAuthPolicyRespParse->pStatusData, pGetAuthPolicyRespParse->statusDataLen) == 0) { pGetAuthPolicyRespParse->status = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_NOT_CONFIGURED); } else if (strncmp(HTTP_SERVER_ERROR_STATUS_CODE, pGetAuthPolicyRespParse->pStatusData, pGetAuthPolicyRespParse->statusDataLen) == 0) { pGetAuthPolicyRespParse->status = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_SERVER_ERROR); } else { DbgTrace(0, "-GetAuthPolicyRespEndElementHandler- Un-expected status\n", 0); pGetAuthPolicyRespParse->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(pGetAuthPolicyRespParse->status)) { // The request completed successfully pGetAuthPolicyRespParse->state = AWAITING_AUTH_POLICY_ELEMENT_START; } else { pGetAuthPolicyRespParse->state = AWAITING_ROOT_ELEMENT_END; } } else { DbgTrace(0, "-GetAuthPolicyRespEndElementHandler- Un-expected element\n", 0); XML_StopParser(pGetAuthPolicyRespParse->p, XML_FALSE); } break; case AWAITING_AUTH_POLICY_ELEMENT_END: // In this state, we are only expecting the Authentication Policy Element. if (strcmp(name, AUTH_POLICY_ELEMENT_NAME) == 0) { // Good, advance to the next state. pGetAuthPolicyRespParse->state = AWAITING_ROOT_ELEMENT_END; } else { DbgTrace(0, "-GetAuthPolicyRespEndElementHandler- Un-expected element\n", 0); XML_StopParser(pGetAuthPolicyRespParse->p, XML_FALSE); } break; default: DbgTrace(0, "-GetAuthPolicyRespEndElementHandler- Un-expected state = %d\n", pGetAuthPolicyRespParse->state); XML_StopParser(pGetAuthPolicyRespParse->p, XML_FALSE); break; } DbgTrace(2, "-GetAuthPolicyRespEndElementHandler- End\n", 0); } //++======================================================================= CasaStatus CreateGetAuthPolicyResp( IN char *pRespMsg, IN size_t respLen, INOUT GetAuthPolicyResp **ppGetAuthPolicyResp) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { CasaStatus retStatus = CASA_STATUS_SUCCESS; GetAuthPolicyRespParse getAuthPolicyRespParse = {0}; GetAuthPolicyResp *pGetAuthPolicyResp; DbgTrace(1, "-CreateGetAuthPolicyResp- Start\n", 0); /* * When a get authentication policy request is processed successfully, the * server replies to the client with a message with the following format: * * * * ok200 * authentication policy data * * * When a get authentication policy 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, "-CreateGetAuthPolicyResp- Response too large\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_INFORMATIONAL, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_UNSUCCESSFUL); goto exit; } // Allocate GetAuthPolicyResp object pGetAuthPolicyResp = malloc(sizeof(*pGetAuthPolicyResp)); if (pGetAuthPolicyResp) { XML_Parser p; // Initialize the GetAuthPolicyResp object and set it in the // parse oject. memset(pGetAuthPolicyResp, 0, sizeof(*pGetAuthPolicyResp)); getAuthPolicyRespParse.pGetAuthPolicyResp = pGetAuthPolicyResp; // Create parser p = XML_ParserCreate(NULL); if (p) { // Keep track of the parser in our parse object getAuthPolicyRespParse.p = p; // Initialize the status within the parse object getAuthPolicyRespParse.status = CASA_STATUS_SUCCESS; // Set the start and end element handlers XML_SetElementHandler(p, (XML_StartElementHandler) GetAuthPolicyRespStartElementHandler, (XML_EndElementHandler) GetAuthPolicyRespEndElementHandler); // Set the character data handler XML_SetCharacterDataHandler(p, (XML_CharacterDataHandler) GetAuthPolicyRespCharDataHandler); // Set our user data XML_SetUserData(p, &getAuthPolicyRespParse); // Parse the document if (XML_Parse(p, pRespMsg, respLen, 1) == XML_STATUS_OK) { // Verify that the parse operation completed successfully if (getAuthPolicyRespParse.state == DONE_PARSING) { // The parse operation succeded, obtain the status returned // by the server. retStatus = getAuthPolicyRespParse.status; } else { DbgTrace(0, "-CreateGetAuthPolicyResp- Parse operation did not complete\n", 0); // Check if a status has been recorded if (getAuthPolicyRespParse.status != CASA_STATUS_SUCCESS) { retStatus = getAuthPolicyRespParse.status; } else { retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_PROTOCOL_ERROR); } } } else { DbgTrace(0, "-CreateGetAuthPolicyResp- 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 (getAuthPolicyRespParse.pStatusData) free(getAuthPolicyRespParse.pStatusData); } else { DbgTrace(0, "-CreateGetAuthPolicyResp- 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)) { *ppGetAuthPolicyResp = pGetAuthPolicyResp; } else { free(pGetAuthPolicyResp); } } else { DbgTrace(0, "-CreateGetAuthPolicyResp- Memory allocation error\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_INSUFFICIENT_RESOURCES); } exit: DbgTrace(1, "-CreateGetAuthPolicyResp- End, retStatus = %08X\n", retStatus); return retStatus; } //++======================================================================= void RelGetAuthPolicyResp( IN GetAuthPolicyResp *pGetAuthPolicyResp) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { DbgTrace(1, "-RelGetAuthPolicyResp- Start\n", 0); // Free the buffer holding the authentication policy if (pGetAuthPolicyResp->pPolicy) free(pGetAuthPolicyResp->pPolicy); // Free the GetAuthPolicyResp free(pGetAuthPolicyResp); DbgTrace(1, "-RelGetAuthPolicyResp- End\n", 0); } //++======================================================================= //++======================================================================= //++=======================================================================