/* * Copyright 2002-2005 The Apache Software Foundation. * * Licensed 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: XSECSafeBuffer.cpp 351214 2005-02-03 13:58:14Z milan $ * */ // XSEC includes #include #include #include #include #include #include XSEC_USING_XERCES(XMLString); XSEC_USING_XERCES(ArrayJanitor); // Standard includes #include #include size_t safeBuffer::size_XMLCh; #if defined (_MSC_VER) #pragma warning(disable: 4311) #endif void safeBuffer::checkAndExpand(unsigned int size) { // For a given size, check it will fit (with one byte spare) // and expand if necessary if (size + 1 < bufferSize) return; // Make the new size twice the size of the new string requirement int newBufferSize = size * 2; unsigned char * newBuffer = new unsigned char[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(unsigned int sz) { checkAndExpand(sz); } safeBuffer::safeBuffer(int initialSize) { // Initialise the buffer with a set size string bufferSize = initialSize; buffer = new unsigned char[initialSize]; mp_XMLCh = NULL; m_isSensitive = false; } safeBuffer::safeBuffer() { bufferSize = DEFAULT_SAFE_BUFFER_SIZE; buffer = new unsigned char[bufferSize]; mp_XMLCh = NULL; m_bufferType = BUFFER_UNKNOWN; m_isSensitive = false; } safeBuffer::safeBuffer(const char * inStr, unsigned int initialSize) { // Initialise with a string bufferSize = ((unsigned int) strlen(inStr) > initialSize ? (unsigned int) (strlen(inStr) * 2) : initialSize); buffer = new unsigned char[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((unsigned int) strlen(inStr)); strcpy((char *) buffer, inStr); m_bufferType = BUFFER_CHAR; } void safeBuffer::sbStrcpyIn(const safeBuffer & inStr) { inStr.checkBufferType(BUFFER_CHAR); checkAndExpand((unsigned int) strlen((char *) inStr.buffer)); strcpy((char *) buffer, (char *) inStr.buffer); m_bufferType = BUFFER_CHAR; } void safeBuffer::sbStrncpyIn(const char * inStr, int n) { int len = (int) strlen(inStr); checkAndExpand((n < len) ? n : len); strncpy((char *) buffer, inStr, n); m_bufferType = BUFFER_CHAR; } void safeBuffer::sbStrncpyIn(const safeBuffer & inStr, int 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((unsigned int) (strlen((char *) buffer) + strlen(inStr))); strcat((char *) buffer, inStr); } void safeBuffer::sbStrcatIn(const safeBuffer & inStr) { checkBufferType(BUFFER_CHAR); checkAndExpand((unsigned int) (strlen((char *) buffer) + strlen((char *) inStr.buffer) + 2)); strcat((char *) buffer, (char *) inStr.buffer); } void safeBuffer::sbStrncatIn(const char * inStr, int n) { checkBufferType(BUFFER_CHAR); int len = (int) strlen(inStr); checkAndExpand(((n < len) ? n : len) + (unsigned int) strlen((char *) buffer) + 2); strncat((char *) buffer, inStr, n); } void safeBuffer::sbMemcpyIn(const void * inBuf, int n) { checkAndExpand(n); memcpy(buffer, inBuf, n); m_bufferType = BUFFER_UNKNOWN; } void safeBuffer::sbMemcpyIn(int offset, const void * inBuf, int n) { checkAndExpand(n + offset); memcpy(&buffer[offset], inBuf, n); m_bufferType = BUFFER_UNKNOWN; } void safeBuffer::sbStrinsIn(const char * inStr, unsigned int offset) { checkBufferType(BUFFER_CHAR); unsigned int bl = (unsigned int) strlen((char *) buffer); unsigned int il = (unsigned int) strlen((char *) inStr); if (offset > bl) { throw XSECException(XSECException::SafeBufferError, "Attempt to insert string after termination point"); } checkAndExpand(bl + il); memmove(&buffer[offset + il], &buffer[offset], bl - offset + 1); memcpy(&buffer[offset], inStr, il); } void safeBuffer::sbStrinsIn(const XMLCh * inStr, unsigned int offset) { checkBufferType(BUFFER_UNICODE); unsigned int bl = XMLString::stringLen((XMLCh *) buffer) * size_XMLCh; unsigned int il = XMLString::stringLen((XMLCh *) inStr) * size_XMLCh; unsigned int xoffset = offset * size_XMLCh; if (xoffset > bl) { throw XSECException(XSECException::SafeBufferError, "Attempt to insert string after termination point"); } checkAndExpand(bl + il); memmove(&buffer[xoffset + il], &buffer[xoffset], bl - xoffset + size_XMLCh); memcpy(&buffer[xoffset], inStr, il); } void safeBuffer::sbMemcpyOut(void *outBuf, int n) const { // WARNING - JUST ASSUMES OUTPUT BUFFER LONG ENOUGH // ALSO MAKES NO ASSUMPTION OF THE BUFFER TYPE memcpy(outBuf, buffer, n); } void safeBuffer::sbMemshift(int toOffset, int fromOffset, int len) { // Move data in the buffer around checkAndExpand((toOffset > fromOffset ? toOffset : fromOffset) + len); memmove(&buffer[toOffset], &buffer[fromOffset], len); } // Comparisons int safeBuffer::sbStrncmp(const char *inStr, int 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, unsigned int offset) const { checkBufferType(BUFFER_CHAR); unsigned int bl = (unsigned int) strlen((char *) buffer); if (offset > bl) return -1; return (strcmp((char *) &buffer[offset], inStr)); } int safeBuffer::sbOffsetStrncmp(const char * inStr, unsigned int offset, int n) const { checkBufferType(BUFFER_CHAR); unsigned int bl = (unsigned int) strlen((char *) buffer); if (offset > bl) return -1; return (strncmp((char *) &buffer[offset], inStr, n)); } int safeBuffer::sbStrstr(const char * inStr) const { char * p; long int d; checkBufferType(BUFFER_CHAR); p = strstr((char *) buffer, inStr); if (p == NULL) return -1; d = (unsigned long int) p - (unsigned long int) buffer; if (d < 0 || (unsigned int) d > bufferSize) return -1; return d; } int safeBuffer::sbStrstr(const XMLCh * inStr) const { XMLCh * p; long int d; checkBufferType(BUFFER_UNICODE); p = XMLString::findAny((XMLCh *) buffer, inStr); if (p == NULL) return -1; d = ((unsigned long int) ((p - (unsigned long int) buffer)) / size_XMLCh); if (d < 0 || (unsigned int) d > bufferSize) return -1; return d; } int safeBuffer::sbOffsetStrstr(const char * inStr, unsigned int offset) const { char * p; long int d; checkBufferType(BUFFER_CHAR); unsigned int bl = (unsigned int) strlen((char *) buffer); if (offset > bl) return -1; p = strstr((char *) &buffer[offset], inStr); if (p == NULL) return -1; d = (unsigned long int) p - (unsigned long int) buffer; if (d < 0 || (unsigned int) d > bufferSize) 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) { unsigned int i; unsigned int l = (unsigned int) strlen((char *) buffer); for (i = 0; i < l; ++i) { if (buffer[i] >= 'A' && buffer[i] <= 'Z') buffer[i] = (buffer[i] - 'A') + 'a'; } } else { unsigned int i; XMLCh * b = (XMLCh *) buffer; unsigned int 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[](int 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" if (n < 0) return buffer[0]; // Should raise exception 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 unsigned offset = 0; unsigned char inBuf[2048]; unsigned int 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) { 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 unsigned int len = (unsigned int) 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 unsigned int len = XMLString::stringLen(t) + 1; len *= (unsigned int) 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); unsigned int 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); unsigned int len = XMLString::stringLen((XMLCh *) buffer) * size_XMLCh; len += XMLString::stringLen(str) * size_XMLCh; len += (2 * ((unsigned int) size_XMLCh)); checkAndExpand(len); XMLString::catString((XMLCh *) buffer, str); } void safeBuffer::sbXMLChCat(const char * str) { checkBufferType(BUFFER_UNICODE); unsigned int len = XMLString::stringLen((XMLCh *) buffer) * size_XMLCh; XMLCh * t = XMLString::transcode(str); assert (t != NULL); len += XMLString::stringLen(t); len += (unsigned int) (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); ArrayJanitor j_toAdd(toAdd); sbXMLChCat(toAdd); } // Get functions int safeBuffer::sbStrlen(void) const { checkBufferType(BUFFER_CHAR); return (int) (strlen ((char *) buffer)); } unsigned int 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 (unsigned int i = 0; i < bufferSize; ++i) buffer[i] = 0; }