/*********************************************************************** * File: util.c * Author: Juan Carlos Luciani (jluciani@novell.com) * * Abstract: Implements common utility functions for the library. * * Copyright (C) 2005 Novell, Inc. * * 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 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, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * To contact Novell about this file by physical or electronic mail, * you may find current contact information at www.novell.com. ***********************************************************************/ //===[ Include files ]===================================================== #include "internal.h" #include //===[ Type definitions ]================================================== //===[ Function prototypes ]=============================================== //===[ Global variables ]================================================== // Debug Level int DebugLevel = 1; // Mechanism OID gss_OID g_mechOid = GSS_C_NULL_OID; // Tables for Base64 encoding and decoding static const int8_t g_Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const uint8_t g_Expand64[256] = { /* ASCII table */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 }; /* ************************************************************************ * LogError() * * Log error to system log. * * ************************************************************************/ //static void //LogError(char *pFormatStr, ... ) //{ // va_list args; // // openlog("CASA", LOG_CONS | LOG_NOWAIT | LOG_ODELAY, LOG_USER); // va_start(args, pFormatStr); // vsyslog(LOG_USER | LOG_INFO, pFormatStr, args); // va_end(args); // closelog(); //} //++======================================================================= void LogGssStatuses( IN char *operation, IN OM_uint32 majorGssStatus, IN OM_uint32 minorGssStatus) // // Arguments: // // Returns: // // Description: // // L2 //=======================================================================-- { OM_uint32 gssMajStat; OM_uint32 gssMinStat; gss_buffer_desc msg = GSS_C_EMPTY_BUFFER; OM_uint32 gssMsgCtx; // Trace the messages associated with the major status gssMsgCtx = 0; while (1) { gssMajStat = gss_display_status(&gssMinStat, majorGssStatus, GSS_C_GSS_CODE, g_mechOid, &gssMsgCtx, &msg); if (gssMajStat != GSS_S_COMPLETE) { DbgTrace(0, "krb5_token -LogGssStatuses- Error obtaining display status\n", 0); break; } // Trace this message DbgTrace(0, "krb5_token -LogGssStatuses- GSS-API error %s: ", operation); DbgTrace(0, "%s\n", (char *)msg.value); if (msg.length != 0) gss_release_buffer(&gssMinStat, &msg); if (!gssMsgCtx) break; } // Trace the messages associated with the minor status gssMsgCtx = 0; while (1) { gssMajStat = gss_display_status(&gssMinStat, minorGssStatus, GSS_C_MECH_CODE, g_mechOid, &gssMsgCtx, &msg); if (gssMajStat != GSS_S_COMPLETE) { DbgTrace(0, "krb5_token -LogGssStatuses- Error obtaining display status\n", 0); break; } // Trace this message DbgTrace(0, "krb5_token -LogGssStatuses- GSS-API error %s: ", operation); DbgTrace(0, "%s\n", (char *)msg.value); if (msg.length != 0) gss_release_buffer(&gssMinStat, &msg); if (!gssMsgCtx) break; } } //++======================================================================= CasaStatus EncodeData( IN const void *pData, IN const int32_t dataLen, INOUT char **ppEncodedData, INOUT int32_t *pEncodedDataLen) // // Arguments: // // Returns: // // Description: // // L2 //=======================================================================-- { CasaStatus retStatus; int encodedSize; DbgTrace(3, "krb5_token -EncodeData- Start\n", 0); // Determine the encoded size and allocate a buffer to hold the encoded data encodedSize = ((dataLen * 4 + 2) / 3) - (dataLen % 3 ) + 4; *ppEncodedData = malloc(encodedSize); if (*ppEncodedData) { uint8_t *pOut, *pIn; int i; // Setup pointers to move through the buffers pIn = (uint8_t*) pData; pOut = (uint8_t*) *ppEncodedData; // Perform the encoding for (i = 0; i < dataLen - 2; i += 3) { *pOut++ = g_Base64[(pIn[i] >> 2) & 0x3F]; *pOut++ = g_Base64[((pIn[i] & 0x3) << 4) | ((int32_t)(pIn[i + 1] & 0xF0) >> 4)]; *pOut++ = g_Base64[((pIn[i + 1] & 0xF) << 2) | ((int32_t)(pIn[i + 2] & 0xC0) >> 6)]; *pOut++ = g_Base64[pIn[i + 2] & 0x3F]; } if (i < dataLen) { *pOut++ = g_Base64[(pIn[i] >> 2) & 0x3F]; if (i == (dataLen - 1)) { *pOut++ = g_Base64[((pIn[i] & 0x3) << 4)]; *pOut++ = '='; } else { *pOut++ = g_Base64[((pIn[i] & 0x3) << 4) | ((int32_t)(pIn[i + 1] & 0xF0) >> 4)]; *pOut++ = g_Base64[((pIn[i + 1] & 0xF) << 2)]; } *pOut++ = '='; } *pOut++ = '\0'; // Return the encoded data length *pEncodedDataLen = (int32_t)(pOut - (uint8_t*)*ppEncodedData); // Success retStatus = CASA_STATUS_SUCCESS; } else { DbgTrace(0, "krb5_token -EncodeData- Buffer allocation failure\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_KRB5TOKEN, CASA_STATUS_INSUFFICIENT_RESOURCES); } DbgTrace(3, "krb5_token -EncodeData- End, retStatus = %08X\n", retStatus); return retStatus; } //++======================================================================= CasaStatus DecodeData( IN const char *pEncodedData, IN const int32_t encodedDataLen, // Does not include NULL terminator INOUT void **ppData, INOUT int32_t *pDataLen) // // Arguments: // // Returns: // // Description: // // L2 //=======================================================================-- { CasaStatus retStatus; int i, j; int decodedSize; DbgTrace(3, "krb5_token -DecodeData- Start\n", 0); // Determine the decoded size for (i = 0, j = 0; i < encodedDataLen; i++) if (g_Expand64[((uint8_t*) pEncodedData)[i]] < 64) j++; decodedSize = (j * 3 + 3) / 4; // Allocate buffer to hold the decoded data *ppData = malloc(decodedSize); if (*ppData) { bool endReached = false; uint8_t c0, c1, c2, c3; uint8_t *p, *q; // Initialize parameters that will be used during the decode operation c0 = c1 = c2 = c3 = 0; p = (uint8_t*) pEncodedData; q = (uint8_t*) *ppData; // Decode the data // // Loop through the data, piecing back information. Any newlines, and/or // carriage returns need to be skipped. while (j > 4) { while ((64 == g_Expand64[*p]) && (('\n' == *p) || ('\r' == *p))) p++; if (64 == g_Expand64[*p]) { endReached = true; break; } c0 = *(p++); while ((64 == g_Expand64[*p]) && (('\n' == *p) || ('\r' == *p))) p++; if (64 == g_Expand64[*p]) { *(q++) = (uint8_t)(g_Expand64[c0] << 2); j--; endReached = true; break; } c1 = *(p++); while ((64 == g_Expand64[*p]) && (('\n' == *p) || ('\r' == *p))) p++; if (64 == g_Expand64[*p]) { *(q++) = (uint8_t)(g_Expand64[c0] << 2 | g_Expand64[c1] >> 4); *(q++) = (uint8_t)(g_Expand64[c1] << 4); j -= 2; endReached = true; break; } c2 = *(p++); while ((64 == g_Expand64[*p]) && (('\n' == *p) || ('\r' == *p))) p++; if (64 == g_Expand64[*p]) { *(q++) = (uint8_t)(g_Expand64[c0] << 2 | g_Expand64[c1] >> 4); *(q++) = (uint8_t)(g_Expand64[c1] << 4 | g_Expand64[c2] >> 2); *(q++) = (uint8_t)(g_Expand64[c2] << 6); j -= 3; endReached = true; break; } c3 = *(p++); *(q++) = (uint8_t)(g_Expand64[c0] << 2 | g_Expand64[c1] >> 4); *(q++) = (uint8_t)(g_Expand64[c1] << 4 | g_Expand64[c2] >> 2); *(q++) = (uint8_t)(g_Expand64[c2] << 6 | g_Expand64[c3]); j -= 4; } if (!endReached) { if (j > 1) *(q++) = (uint8_t)(g_Expand64[*p] << 2 | g_Expand64[p[1]] >> 4); if (j > 2) *(q++) = (uint8_t)(g_Expand64[p[1]] << 4 | g_Expand64[p[2]] >> 2); if (j > 3) *(q++) = (uint8_t)(g_Expand64[p[2]] << 6 | g_Expand64[p[3]]); } // Return the length of the decoded data *pDataLen = (int32_t)(q - (uint8_t*)*ppData); // Success retStatus = CASA_STATUS_SUCCESS; } else { DbgTrace(0, "krb5_token -DecodeData- Buffer allocation failure\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_KRB5TOKEN, CASA_STATUS_INSUFFICIENT_RESOURCES); } DbgTrace(3, "krb5_token -DecodeData- End, retStatus = %08X\n", retStatus); return retStatus; } //++======================================================================= //++======================================================================= //++=======================================================================