blob: 52c2fd2a0cf41626f6bfc571f76454caec8c296b [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/*
* XSEC
*
* XSECSafeBuffer := a class for storing expanding amounts of information.
*
* Author(s): Berin Lautenbach
*
* $Id$
*
*/
// XSEC includes
#include <xsec/utils/XSECSafeBuffer.hpp>
#include <xsec/framework/XSECError.hpp>
#include <xsec/transformers/TXFMBase.hpp>
#include "XSECDOMUtils.hpp"
#include <xercesc/util/XMLUniDefs.hpp>
XSEC_USING_XERCES(XMLString);
// Standard includes
#include <stdlib.h>
#include <string.h>
size_t safeBuffer::size_XMLCh;
#if defined (_MSC_VER)
#pragma warning(disable: 4311)
#endif
void safeBuffer::checkAndExpand(XMLSize_t size) {
// For a given size, check it will fit (with one byte spare)
// and expand if necessary
if (bufferSize >= 2 && size < bufferSize - 2) {
return;
}
if (size > XERCES_SIZE_MAX - DEFAULT_SAFE_BUFFER_SIZE) {
/* We've got a string that's too big to deal with */
throw XSECException(XSECException::SafeBufferError,
"Buffer has grown too large");
}
// Resize and add 1K for further growth
XMLSize_t newBufferSize = size + DEFAULT_SAFE_BUFFER_SIZE;
unsigned char * newBuffer = new unsigned char[newBufferSize];
if (newBuffer == NULL)
{
/* Ran out of memory */
throw XSECException(XSECException::MemoryAllocationFail,
"Error allocating memory for Buffer");
}
memset((void *) newBuffer, 0, newBufferSize);
memcpy(newBuffer, buffer, bufferSize);
// If we are sensitive, clean the old buffer
if (m_isSensitive == true)
cleanseBuffer();
// clean up
bufferSize = newBufferSize;
delete[] buffer;
buffer = newBuffer;
}
void safeBuffer::checkBufferType(bufferType bt) const {
if (bt != m_bufferType) {
throw XSECException(XSECException::SafeBufferError,
"Attempt to perform an operation on a buffer of incorrect type");
}
}
void safeBuffer::setBufferType(bufferType bt) {
m_bufferType = bt;
}
void safeBuffer::resize(XMLSize_t sz) {
checkAndExpand(sz);
}
safeBuffer::safeBuffer(XMLSize_t initialSize) {
// Initialise the buffer with a set size string
bufferSize = initialSize;
buffer = new unsigned char[initialSize];
memset((void *) buffer, 0, bufferSize);
mp_XMLCh = NULL;
m_bufferType = BUFFER_UNKNOWN;
m_isSensitive = false;
}
safeBuffer::safeBuffer() {
bufferSize = DEFAULT_SAFE_BUFFER_SIZE;
buffer = new unsigned char[bufferSize];
memset((void *) buffer, 0, bufferSize);
mp_XMLCh = NULL;
m_bufferType = BUFFER_UNKNOWN;
m_isSensitive = false;
}
safeBuffer::safeBuffer(const char * inStr, XMLSize_t initialSize) {
// Initialise with a string
bufferSize = ((XMLSize_t) strlen(inStr) > initialSize ? (XMLSize_t) (strlen(inStr) * 2) : initialSize);
buffer = new unsigned char[bufferSize];
memset((void *) buffer, 0, bufferSize);
strcpy((char *) buffer, inStr);
mp_XMLCh = NULL;
m_bufferType = BUFFER_CHAR;
m_isSensitive = false;
}
safeBuffer::safeBuffer(const safeBuffer & other) {
// Copy constructor
bufferSize = other.bufferSize;
buffer = new unsigned char [bufferSize];
memcpy(buffer, other.buffer, bufferSize);
if (other.mp_XMLCh != NULL) {
mp_XMLCh = XMLString::replicate(other.mp_XMLCh);
}
else {
mp_XMLCh = NULL;
}
m_bufferType = other.m_bufferType;
m_isSensitive = other.m_isSensitive;
}
safeBuffer::~safeBuffer() {
if (buffer != NULL) {
if (m_isSensitive == true)
cleanseBuffer();
delete[] buffer;
}
if (mp_XMLCh != NULL)
XSEC_RELEASE_XMLCH(mp_XMLCh);
}
void safeBuffer::init (void) {
size_XMLCh = sizeof(XMLCh);
}
// "IN" functions - these read in information to the buffer
void safeBuffer::sbStrcpyIn(const char * inStr) {
// Copy a string into the safe buffer
checkAndExpand((XMLSize_t) strlen(inStr));
strcpy((char *) buffer, inStr);
m_bufferType = BUFFER_CHAR;
}
void safeBuffer::sbStrcpyIn(const safeBuffer & inStr) {
inStr.checkBufferType(BUFFER_CHAR);
checkAndExpand((XMLSize_t) strlen((char *) inStr.buffer));
strcpy((char *) buffer, (char *) inStr.buffer);
m_bufferType = BUFFER_CHAR;
}
void safeBuffer::sbStrncpyIn(const char * inStr, XMLSize_t n) {
XMLSize_t len = (XMLSize_t) strlen(inStr);
checkAndExpand((n < len) ? n : len);
strncpy((char *) buffer, inStr, n);
buffer[n] = '\0';
m_bufferType = BUFFER_CHAR;
}
void safeBuffer::sbStrncpyIn(const safeBuffer & inStr, XMLSize_t n) {
inStr.checkBufferType(BUFFER_CHAR);
checkAndExpand(n);
strncpy((char *) buffer, (char *) inStr.buffer, n);
buffer[n] = '\0';
m_bufferType = BUFFER_CHAR;
}
void safeBuffer::sbStrcatIn(const char * inStr) {
checkBufferType(BUFFER_CHAR);
checkAndExpand((XMLSize_t) (strlen((char *) buffer) + strlen(inStr) + 1));
strcat((char *) buffer, inStr);
}
void safeBuffer::sbStrcatIn(const safeBuffer & inStr) {
checkBufferType(BUFFER_CHAR);
checkAndExpand((XMLSize_t) (strlen((char *) buffer) + strlen((char *) inStr.buffer) + 2));
strcat((char *) buffer, (char *) inStr.buffer);
}
void safeBuffer::sbStrncatIn(const char * inStr, XMLSize_t n) {
checkBufferType(BUFFER_CHAR);
XMLSize_t len = (XMLSize_t) strlen(inStr);
XMLSize_t totalLen = ((n < len) ? n : len) + (XMLSize_t)strlen((char *)buffer);
checkAndExpand(totalLen + 2);
strncat((char *) buffer, inStr, n);
buffer[totalLen] = '\0';
}
void safeBuffer::sbMemcpyIn(const void * inBuf, XMLSize_t n) {
checkAndExpand(n);
memcpy(buffer, inBuf, n);
m_bufferType = BUFFER_UNKNOWN;
}
void safeBuffer::sbMemcpyIn(XMLSize_t offset, const void * inBuf, XMLSize_t n) {
checkAndExpand(n + offset);
memcpy(&buffer[offset], inBuf, n);
m_bufferType = BUFFER_UNKNOWN;
}
void safeBuffer::sbStrinsIn(const char * inStr, XMLSize_t offset) {
checkBufferType(BUFFER_CHAR);
XMLSize_t bl = (XMLSize_t) strlen((char *) buffer);
XMLSize_t il = (XMLSize_t) strlen((char *) inStr);
if (offset > bl) {
throw XSECException(XSECException::SafeBufferError,
"Attempt to insert string after termination point");
}
checkAndExpand(bl + il + 1);
memmove(&buffer[offset + il], &buffer[offset], bl - offset + 1);
memcpy(&buffer[offset], inStr, il);
}
void safeBuffer::sbMemcpyOut(void *outBuf, XMLSize_t n) const {
// WARNING - JUST ASSUMES OUTPUT BUFFER LONG ENOUGH
// ALSO MAKES NO ASSUMPTION OF THE BUFFER TYPE
if (n > bufferSize) {
throw XSECException(XSECException::SafeBufferError,
"safeBuffer::sbMemcpyOut Attempt to copy more data than buffer can hold");
}
memcpy(outBuf, buffer, n);
}
void safeBuffer::sbMemshift(XMLSize_t toOffset, XMLSize_t fromOffset, XMLSize_t len) {
// Move data in the buffer around
checkAndExpand(len + (toOffset > fromOffset ? toOffset : fromOffset));
memmove(&buffer[toOffset], &buffer[fromOffset], len);
}
// Comparisons
int safeBuffer::sbStrncmp(const char *inStr, XMLSize_t n) const {
checkBufferType(BUFFER_CHAR);
return (strncmp((char *) buffer, inStr, n));
}
int safeBuffer::sbStrcmp(const char *inStr) const {
checkBufferType(BUFFER_CHAR);
return (strcmp((char *) buffer, inStr));
}
int safeBuffer::sbStrcmp(const safeBuffer & inStr) const {
checkBufferType(BUFFER_CHAR);
return (strcmp((char *) buffer, (char *) inStr.buffer));
}
int safeBuffer::sbOffsetStrcmp(const char * inStr, XMLSize_t offset) const {
checkBufferType(BUFFER_CHAR);
XMLSize_t bl = (XMLSize_t) strlen((char *) buffer);
if (offset > bl)
return -1;
return (strcmp((char *) &buffer[offset], inStr));
}
XMLSSize_t safeBuffer::sbStrstr(const char * inStr) const {
checkBufferType(BUFFER_CHAR);
const char* p = strstr((char *) buffer, inStr);
if (p == NULL)
return -1;
XMLSSize_t d = p - (char*) buffer;
if (d > bufferSize || d < 0)
return -1;
return d;
}
XMLSSize_t safeBuffer::sbOffsetStrstr(const char * inStr, XMLSize_t offset) const {
checkBufferType(BUFFER_CHAR);
XMLSize_t bl = strlen((char *) buffer);
if (offset > bl)
return -1;
const char* p = strstr((char *) &buffer[offset], inStr);
if (p == NULL)
return -1;
XMLSSize_t d = p - (char*) buffer;
if (d > bufferSize || d < 0)
return -1;
return d;
}
// XMLCh and char common functions
void safeBuffer::sbStrlwr(void) {
if (m_bufferType == BUFFER_UNKNOWN) {
throw XSECException(XSECException::SafeBufferError,
"Attempt to perform an operation on a buffer of incorrect type");
}
if (m_bufferType == BUFFER_CHAR) {
XMLSize_t i, l = (XMLSize_t) strlen((char *) buffer);
for (i = 0; i < l; ++i) {
if (buffer[i] >= 'A' && buffer[i] <= 'Z')
buffer[i] = (buffer[i] - 'A') + 'a';
}
}
else {
XMLCh * b = (XMLCh *) buffer;
XMLSize_t i, l = XMLString::stringLen(b);
for (i = 0; i < l; ++i) {
if (b[i] >= XERCES_CPP_NAMESPACE_QUALIFIER chLatin_A && b[i] <= XERCES_CPP_NAMESPACE_QUALIFIER chLatin_Z)
b[i] = (b[i] - XERCES_CPP_NAMESPACE_QUALIFIER chLatin_A) + XERCES_CPP_NAMESPACE_QUALIFIER chLatin_a;
}
}
}
// Operators
unsigned char & safeBuffer::operator[](XMLSize_t n) {
// If the character is outside our range (but +ve), then simply increase
// the buffer size - NOTE: it is not our problem if the caller does
// not realise they are outside the buffer, we are simply trying to ensure
// the call is "safe"
checkAndExpand(n);
return buffer[n];
}
safeBuffer & safeBuffer::operator= (const safeBuffer & cpy) {
if (bufferSize != cpy.bufferSize) {
if (bufferSize != 0) {
if (m_isSensitive == true)
cleanseBuffer();
delete [] buffer;
}
buffer = new unsigned char [cpy.bufferSize];
bufferSize = cpy.bufferSize;
}
memcpy(buffer, cpy.buffer, bufferSize);
m_bufferType = cpy.m_bufferType;
// Once we are sensitive, we are always sensitive
m_isSensitive = m_isSensitive || cpy.m_isSensitive;
return *this;
}
safeBuffer & safeBuffer::operator= (const XMLCh * inStr) {
checkAndExpand(XMLString::stringLen(inStr) * size_XMLCh);
XMLString::copyString((XMLCh *) buffer, inStr);
m_bufferType = BUFFER_UNICODE;
return *this;
}
safeBuffer & safeBuffer::operator << (TXFMBase * t) {
// Read into buffer the output of the transform
XMLSize_t offset = 0;
unsigned char inBuf[2048];
XMLSize_t bytesRead;
while ((bytesRead = t->readBytes(inBuf, 2000)) > 0) {
checkAndExpand(offset + bytesRead + 1);
memcpy(&buffer[offset], inBuf, bytesRead);
offset += bytesRead;
}
m_bufferType = BUFFER_CHAR;
buffer[offset] = '\0';
return *this;
}
// Unicode Functions
const XMLCh * safeBuffer::sbStrToXMLCh(void) const {
checkBufferType(BUFFER_CHAR);
if (mp_XMLCh != NULL)
XSEC_RELEASE_XMLCH(mp_XMLCh);
mp_XMLCh = XMLString::transcode((char *) buffer);
return mp_XMLCh;
}
void safeBuffer::sbTranscodeIn(const XMLCh * inStr) {
// Transcode the string to the local code page and store in the buffer
char * t;
t = XMLString::transcode(inStr);
assert (t != 0);
// Now copy into our local buffer - a bit inefficient but better in the long run
// as a buffer that is the exact size is likely to be deleted anyway during a
// concat operation
XMLSize_t len = (XMLSize_t) strlen(t) + 1;
checkAndExpand(len);
strcpy((char *) buffer, t);
m_bufferType = BUFFER_CHAR;
XSEC_RELEASE_XMLCH(t);
}
void safeBuffer::sbTranscodeIn(const char * inStr) {
// Transcode the string to the local code page and store in the buffer
XMLCh * t;
t = XMLString::transcode(inStr);
assert (t != 0);
// Copy into local buffer
XMLSize_t len = XMLString::stringLen(t) + 1;
len *= (XMLSize_t) size_XMLCh;
checkAndExpand(len);
XMLString::copyString((XMLCh *) buffer, t);
m_bufferType = BUFFER_UNICODE;
XSEC_RELEASE_XMLCH(t);
}
void safeBuffer::sbXMLChIn(const XMLCh * in) {
checkAndExpand((XMLString::stringLen(in) + 1) * size_XMLCh);
XMLString::copyString((XMLCh *) buffer, in);
m_bufferType = BUFFER_UNICODE;
}
void safeBuffer::sbXMLChAppendCh(const XMLCh c) {
checkBufferType(BUFFER_UNICODE);
XMLSize_t len = XMLString::stringLen((XMLCh *) buffer);
checkAndExpand((len + 2) * size_XMLCh);
((XMLCh *) buffer)[len++] = c;
((XMLCh *) buffer)[len] = 0;
}
void safeBuffer::sbXMLChCat(const XMLCh *str) {
checkBufferType(BUFFER_UNICODE);
XMLSize_t len = XMLString::stringLen((XMLCh *) buffer) * size_XMLCh;
len += XMLString::stringLen(str) * size_XMLCh;
len += (2 * ((XMLSize_t) size_XMLCh));
checkAndExpand(len);
XMLString::catString((XMLCh *) buffer, str);
}
void safeBuffer::sbXMLChCat(const char * str) {
checkBufferType(BUFFER_UNICODE);
XMLSize_t len = XMLString::stringLen((XMLCh *) buffer) * size_XMLCh;
XMLCh * t = XMLString::transcode(str);
assert (t != NULL);
len += XMLString::stringLen(t) * size_XMLCh;
len += (XMLSize_t) (2 * size_XMLCh);
checkAndExpand(len);
XMLString::catString((XMLCh *) buffer, t);
XSEC_RELEASE_XMLCH(t);
}
void safeBuffer::sbXMLChCat8(const char * str) {
checkBufferType(BUFFER_UNICODE);
XMLCh * toAdd = transcodeFromUTF8((const unsigned char *) str);
sbXMLChCat(toAdd);
XSEC_RELEASE_XMLCH(toAdd);
}
// Get functions
XMLSize_t safeBuffer::sbStrlen(void) const {
checkBufferType(BUFFER_CHAR);
return (XMLSize_t) (strlen ((char *) buffer));
}
XMLSize_t safeBuffer::sbRawBufferSize(void) const {
return bufferSize;
}
// raw buffer manipulation
const unsigned char * safeBuffer::rawBuffer() const {
return buffer;
}
const char * safeBuffer::rawCharBuffer() const {
return (char *) buffer;
}
const XMLCh * safeBuffer::rawXMLChBuffer() const {
return (XMLCh *) buffer;
}
// Sensitive data functions
void safeBuffer::isSensitive(void) {
m_isSensitive = true;
}
void safeBuffer::cleanseBuffer(void) {
// Cleanse the main buffer
for (XMLSize_t i = 0; i < bufferSize; ++i)
buffer[i] = 0;
}