📄 stream.c
字号:
#ifndef NO_STDIO
/* It's a file stream, find the position in the file */
#if defined( __WIN32__ )
if( ( position = SetFilePointer( stream->hFile, 0, NULL,
FILE_CURRENT ) ) == 0xFFFFFFFF )
#elif defined( __MAC__ )
if( GetFPos( stream->refNum, &position ) != noErr )
#else
if( ( position = ftell( stream->filePtr ) ) == -1L )
#endif /* __WIN32__ */
return( CRYPT_ERROR_READ );
#else
assert( NOTREACHED );
#endif /* NO_STDIO */
return( position );
}
/* Determine whether a stream is out of data */
int seof( const STREAM *stream )
{
return( stream->status == CRYPT_ERROR_UNDERFLOW );
}
/* Skip a number of bytes in a stream */
int sSkip( STREAM *stream, const long length )
{
long skipLength = length;
assert( stream != NULL && \
( stream->type == STREAM_TYPE_NULL || \
stream->type == STREAM_TYPE_MEMORY || \
stream->type == STREAM_TYPE_FILE ) );
assert( length > 0 );
/* If there's a problem with the stream, don't try to do anything */
if( stream->status != CRYPT_OK )
return( stream->status );
/* If we were ready to unget a char, skip it */
if( stream->ungetChar )
{
stream->ungetChar = FALSE;
stream->lastChar = 0;
skipLength--;
if( skipLength == 0 )
return( CRYPT_OK );
}
/* If it's a memory or null stream, move ahead in the buffer */
if( stream->type == STREAM_TYPE_NULL )
{
stream->bufPos += ( int ) skipLength;
return( CRYPT_OK );
}
if( stream->type == STREAM_TYPE_MEMORY )
{
if( stream->bufSize != STREAMSIZE_UNKNOWN && \
stream->bufPos + skipLength > stream->bufSize )
{
stream->bufPos = stream->bufSize;
stream->status = CRYPT_ERROR_UNDERFLOW;
return( CRYPT_ERROR_UNDERFLOW );
}
stream->bufPos += ( int ) skipLength;
if( stream->bufPos > stream->bufEnd )
/* If we've moved past the end of the valid data in the buffer,
move the end of data pointer to match the current position.
This mimics the behaviour of fseek(), which allows a seek past
the end of the file */
stream->bufEnd = stream->bufPos;
return( CRYPT_OK );
}
#ifndef NO_STDIO
/* It's a file stream, skip the data in the file */
#if defined( __WIN32__ )
if( SetFilePointer( stream->hFile, skipLength, NULL,
FILE_CURRENT ) == 0xFFFFFFFF )
#elif defined( __MAC__ )
if( SetFPos( stream->refNum, fsFromMark, skipLength) != noErr )
#else
if( fseek( stream->filePtr, skipLength, SEEK_CUR ) )
#endif /* __WIN32__ */
{
stream->status = CRYPT_ERROR_READ;
return( CRYPT_ERROR_READ );
}
#endif /* NO_STDIO */
return( CRYPT_OK );
}
/* Perform an IOCTL on a stream */
int sioctl( STREAM *stream, const STREAM_IOCTL_TYPE type, void *data,
const int dataLen )
{
assert( stream != NULL && stream->type == STREAM_TYPE_NETWORK );
assert( type > STREAM_IOCTL_NONE && type < STREAM_IOCTL_LAST );
switch( type )
{
case STREAM_IOCTL_TIMEOUT:
assert( data == NULL );
assert( dataLen >= 0 );
stream->timeout = dataLen;
break;
case STREAM_IOCTL_GETTIMEOUT:
assert( data != NULL );
assert( dataLen == 0 );
*( ( int * ) data ) = stream->timeout;
break;
case STREAM_IOCTL_GETCLIENTNAME:
assert( data != NULL );
assert( dataLen == 0 );
strcpy( data, stream->clientAddress );
break;
case STREAM_IOCTL_GETCLIENTPORT:
assert( data != NULL );
assert( dataLen == 0 );
*( ( int * ) data ) = stream->clientPort;
break;
case STREAM_IOCTL_CONTENTTYPE:
assert( stream->protocol == STREAM_PROTOCOL_HTTP || \
stream->protocol == STREAM_PROTOCOL_HTTP_TRANSACTION );
assert( data != NULL );
assert( dataLen > 0 && dataLen < CRYPT_MAX_TEXTSIZE );
memcpy( stream->contentType, data, dataLen );
stream->contentType[ dataLen ] = '\0';
break;
case STREAM_IOCTL_QUERY:
assert( stream->protocol == STREAM_PROTOCOL_HTTP || \
stream->protocol == STREAM_PROTOCOL_HTTP_TRANSACTION );
assert( data != NULL );
assert( dataLen > 0 && dataLen < CRYPT_MAX_TEXTSIZE );
/* Set up the buffer to contain the query if necessary */
if( stream->queryLen <= dataLen )
{
if( stream->query != NULL )
{
free( stream->query );
stream->queryLen = 0;
}
if( ( stream->query = malloc( max( CRYPT_MAX_TEXTSIZE, \
dataLen + 1 ) ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
stream->queryLen = dataLen;
}
/* Copy in the query */
memcpy( stream->query, data, dataLen );
stream->query[ dataLen ] = '\0';
break;
case STREAM_IOCTL_LASTMESSAGE:
assert( stream->protocol == STREAM_PROTOCOL_CMP );
assert( data == NULL );
assert( dataLen == TRUE );
stream->lastMessage = TRUE;
break;
case STREAM_IOCTL_CALLBACKFUNCTION:
assert( stream->protocol == STREAM_PROTOCOL_HTTP || \
stream->protocol == STREAM_PROTOCOL_HTTP_TRANSACTION );
assert( data != NULL );
assert( dataLen == 0 );
stream->callbackFunction = ( CALLBACKFUNCTION ) data;
break;
case STREAM_IOCTL_CALLBACKPARAMS:
assert( stream->protocol == STREAM_PROTOCOL_HTTP || \
stream->protocol == STREAM_PROTOCOL_HTTP_TRANSACTION );
assert( data != NULL );
assert( dataLen == 0 );
stream->callbackParams = data;
break;
default:
assert( NOTREACHED );
}
return( CRYPT_OK );
}
/****************************************************************************
* *
* Memory Stream Functions *
* *
****************************************************************************/
/* Open a memory stream. If the buffer parameter is NULL and the length is
zero, this creates a null stream which serves as a data sink - this is
useful for implementing sizeof() functions by writing data to null
streams */
int sMemOpen( STREAM *stream, void *buffer, const int length )
{
assert( stream != NULL );
assert( ( buffer == NULL && length == 0 ) || \
( buffer != NULL && \
( length > 1 || length == STREAMSIZE_UNKNOWN ) ) );
memset( stream, 0, sizeof( STREAM ) );
if( buffer == NULL )
{
/* Make it a null stream */
stream->type = STREAM_TYPE_NULL;
return( CRYPT_OK );
}
/* Initialise the stream structure */
stream->type = STREAM_TYPE_MEMORY;
stream->buffer = buffer;
stream->bufSize = length;
if( stream->bufSize != STREAMSIZE_UNKNOWN )
/* The stream buffers can be arbitrarily large so we only clear
the entire buffer in the debug version */
#ifdef NDEBUG
memset( stream->buffer, 0, stream->bufSize );
#else
memset( stream->buffer, 0, min( 256, stream->bufSize ) );
#endif /* NDEBUG */
return( CRYPT_OK );
}
/* Close a memory stream */
int sMemClose( STREAM *stream )
{
assert( stream != NULL && \
( stream->type == STREAM_TYPE_NULL || \
stream->type == STREAM_TYPE_MEMORY ) );
/* Clear the stream structure */
if( stream->buffer != NULL )
if( stream->bufSize != STREAMSIZE_UNKNOWN )
zeroise( stream->buffer, stream->bufSize );
else
/* If it's of an unknown size we can still zap as much as was
written to/read from it */
if( stream->bufEnd > 0 )
zeroise( stream->buffer, stream->bufEnd );
zeroise( stream, sizeof( STREAM ) );
return( CRYPT_OK );
}
/* Connect a memory stream without destroying the buffer contents */
int sMemConnect( STREAM *stream, const void *buffer, const int length )
{
assert( stream != NULL );
assert( buffer != NULL );
assert( length >= 1 || length == STREAMSIZE_UNKNOWN );
/* Initialise the stream structure */
memset( stream, 0, sizeof( STREAM ) );
stream->type = STREAM_TYPE_MEMORY;
stream->buffer = ( void * ) buffer;
stream->bufSize = stream->bufEnd = length;
stream->flags = STREAM_FLAG_READONLY;
return( CRYPT_OK );
}
/* Disconnect a memory stream without destroying the buffer contents */
int sMemDisconnect( STREAM *stream )
{
assert( stream != NULL && \
( stream->type == STREAM_TYPE_NULL || \
stream->type == STREAM_TYPE_MEMORY ) );
/* Clear the stream structure */
memset( stream, 0, sizeof( STREAM ) );
return( CRYPT_OK );
}
/****************************************************************************
* *
* File Stream Functions *
* *
****************************************************************************/
/* Usually we'd use the C stdio routines for file I/O, but we can get
enhanced control over things like file security and buffering by using
OS-level file routines (in fact this is almost essential to work with
things like ACL's for sensitive files and forcing disk writes for files we
want to erase. Without the forced disk write the data in the cache
doesn't get flushed before the file delete request arrives, after which
it's discarded rather than being written, so the file never gets
overwritten). In addition some embedded environments don't support stdio
so we have to supply our own alternatives.
When implementing the following for new systems there are certain things
which you need to ensure to guarantee error-free operation:
- File permissions should be set as indicated by the file open flags.
- File sharing controls (shared vs exclusive access locks) should be
implemented.
- If the file is locked for exclusive access, the open call should either
block until the lock is released (they're never held for more than a
fraction of a second) or return CRYPT_ERROR_BUSY depending on how the
OS handles locks */
/* Open a file stream */
#if defined( __WIN32__ )
/* Get information on the current user. This works in an extraordinarily
ugly manner because although the TOKEN_USER struct is only 8 bytes long,
Windoze allocates an extra 24 bytes after the end of the struct into which
it stuffs data which the SID in the TOKEN_USER struct points to. This
means we can't return the SID pointer from the function because it would
point to freed memory, so we need to return the pointer to the entire
TOKEN_USER struct to ensure that what the SID pointer points to remains
around for the caller to use */
TOKEN_USER *getUserInfo( void )
{
TOKEN_USER *pUserInfo = NULL;
HANDLE hToken = INVALID_HANDLE_VALUE; /* See comment below */
DWORD cbTokenUser;
/* Get the security token for this thread. We initialise the hToken even
though it shouldn't be necessary because Windows tries to read its
contents, which indicates there might be problems if it happens to
have the wrong value */
if( !OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, FALSE, &hToken ) )
{
/* If the thread doesn't have a security token, try the token
associated with the process */
if( ( GetLastError() != ERROR_NO_TOKEN ) || \
!OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &hToken ) )
return( NULL );
}
/* Query the size of the user information associated with the token,
allocate a buffer for it, and fetch the information into the buffer */
GetTokenInformation( hToken, TokenUser, NULL, 0, &cbTokenUser );
if( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
{
pUserInfo = ( TOKEN_USER * ) malloc( cbTokenUser );
if( !GetTokenInformation( hToken, TokenUser, pUserInfo, cbTokenUser,
&cbTokenUser ) )
{
free( pUserInfo );
pUserInfo = NULL;
}
}
/* Clean up */
CloseHandle( hToken );
return( pUserInfo );
}
int sFileOpen( STREAM *stream, const char *fileName, const int mode )
{
SECURITY_ATTRIBUTES sa;
LPSECURITY_ATTRIBUTES lpsa = NULL;
SECURITY_DESCRIPTOR sdPermissions;
TOKEN_USER *pUserInfo = NULL;
BYTE aclBuffer[ ACL_BUFFER_SIZE ];
PACL paclKey = ( PACL ) aclBuffer;
HANDLE hFile;
UINT uErrorMode;
int status;
assert( stream != NULL );
assert( fileName != NULL );
assert( mode != 0 );
/* Initialise the stream structure */
memset( stream, 0, sizeof( STREAM ) );
stream->type = STREAM_TYPE_FILE;
if( ( mode & FILE_RW_MASK ) == FILE_READ )
stream->flags = STREAM_FLAG_READONLY;
/* If we're creating the file and we don't want others to get to it, set
up the security attributes to reflect this provided the OS supports
security */
if( !isWin95 && ( mode & FILE_WRITE ) && ( mode & FILE_PRIVATE ) )
{
/* Get the SID for the current user */
if( ( pUserInfo = getUserInfo() ) == NULL )
return( CRYPT_ERROR_OPEN );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -