📄 str_file.c
字号:
char fileNameBuffer[ MAX_PATH_LENGTH ];
#endif /* EBCDIC_CHARS */
/* Make sure that the open fails if we can't build the path */
*path = '\0';
/* Build the path to the configuration file if necessary */
#ifdef DDNAME_IO
/* MVS dataset name userid.CRYPTLIB.filename. We can't use a PDS since
multiple members have to be opened in write mode simultaneously */
strcpy( path, "//CRYPTLIB." );
strcat( path, fileName );
#else
#ifdef EBCDIC_CHARS
fileName = bufferToEbcdic( fileNameBuffer, fileName );
#pragma convlit( suspend )
#endif /* EBCDIC_CHARS */
/* Get the path to the user's home directory */
if( ( passwd = getpwuid( getuid() ) ) == NULL )
return; /* Huh? User not in passwd file */
if( ( length = strlen( passwd->pw_dir ) ) > MAX_PATH_LENGTH - 64 )
/* You're kidding, right? */
return;
memcpy( path, passwd->pw_dir, length );
if( path[ length - 1 ] != '/' )
path[ length++ ] = '/';
strcpy( path + length, ".cryptlib" );
/* If we're being asked to create the cryptlib directory and it doesn't
already exist, create it now */
if( createPath && access( path, F_OK ) == -1 && \
mkdir( path, 0700 ) == -1 )
{
*path = '\0';
return;
}
/* Add the filename to the path */
strcat( path, "/" );
strcat( path, fileName );
strcat( path, ".p15" );
#ifdef EBCDIC_CHARS
#pragma convlit( resume )
ebcdicToAscii( path, strlen( path ) );
#endif /* EBCDIC_CHARS */
#endif /* OS-specific file path creation */
}
/****************************************************************************
* *
* Macintosh File Stream Functions *
* *
****************************************************************************/
#elif defined( __MAC__ )
/* Convert a C to a Pascal string */
static void CStringToPString( const char *cstring, StringPtr pstring )
{
short len = min( strlen( cstring ), 255 );
memmove( pstring + 1, cstring, len );
*pstring = len;
}
/* Open/close a file stream */
int sFileOpen( STREAM *stream, const char *fileName, const int mode )
{
Str255 pFileName;
OSErr err;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
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;
CStringToPString( fileName, pFileName );
err = FSMakeFSSpec( 0, 0, pFileName, &stream->fsspec );
if( err == dirNFErr || err == nsvErr )
/* Volume or parent directory not found */
return( CRYPT_ERROR_NOTFOUND );
if( err != noErr && err != fnfErr )
/* fnfErr is OK since the fsspec is still valid */
return( CRYPT_ERROR_OPEN );
if( mode & FILE_WRITE )
{
/* Try and create the file, specifying its type and creator. The
wierd string-looking constants are Mac compiler-specific and
evaluate to 32-bit unsigned type and creator IDs */
err = FSpCreate( &stream->fsspec, '????', 'CLib', smSystemScript );
if( err == wPrErr || err == vLckdErr || err == afpAccessDenied )
return( CRYPT_ERROR_PERMISSION );
if( err != noErr && err != dupFNErr && err != afpObjectTypeErr )
return( CRYPT_ERROR_OPEN );
}
err = FSpOpenDF( &stream->fsspec, mode & FILE_RW_MASK, &stream->refNum );
if( err == nsvErr || err == dirNFErr || err == fnfErr )
return( CRYPT_ERROR_NOTFOUND );
if( err == opWrErr || err == permErr || err == afpAccessDenied )
return( CRYPT_ERROR_PERMISSION );
if( err != noErr )
return( CRYPT_ERROR_OPEN );
return( CRYPT_OK );
}
int sFileClose( STREAM *stream )
{
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( stream->type == STREAM_TYPE_FILE );
/* Close the file and clear the stream structure */
FSClose( stream->refNum );
zeroise( stream, sizeof( STREAM ) );
return( CRYPT_OK );
}
/* Read/write a block of data from/to a file stream */
int fileRead( STREAM *stream, void *buffer, const int length )
{
long bytesRead = length;
if( FSRead( stream->refNum, &bytesRead, buffer ) != noErr )
return( CRYPT_ERROR_READ );
return( bytesRead );
}
int fileWrite( STREAM *stream, const void *buffer, const int length )
{
long bytesWritten = length;
if( FSWrite( stream->refNum, &bytesWritten, buffer ) != noErr || \
( int ) bytesWritten != length )
return( CRYPT_ERROR_WRITE );
return( CRYPT_OK );
}
/* Commit data in a file stream to backing storage */
int fileFlush( STREAM *stream )
{
FileParam paramBlock;
paramBlock.ioCompletion = NULL;
paramBlock.ioFRefNum = stream->refNum;
PBFlushFileSync( ( union ParamBlockRec * ) ¶mBlock );
return( CRYPT_OK );
}
/* Change the read/write position in a file */
int fileSeek( STREAM *stream, const long position )
{
if( SetFPos( stream->refNum, fsFromStart, position ) != noErr )
return( CRYPT_ERROR_WRITE );
return( CRYPT_OK );
}
/* Check whether a file is writeable */
BOOLEAN fileReadonly( const char *fileName )
{
Str255 pFileName;
FSSpec fsspec;
OSErr err;
short refnum;
assert( fileName != NULL );
CStringToPString( fileName, pFileName );
err = FSMakeFSSpec( 0, 0, pFileName, &fsspec );
if ( err == noErr )
err = FSpOpenDF( &fsspec, fsRdWrPerm, &refnum );
if ( err == noErr )
FSClose( refnum );
if ( err == opWrErr || err == permErr || err == afpAccessDenied )
return( TRUE );
return( FALSE );
}
/* File deletion functions: Wipe a file from the current position to EOF,
and wipe and delete a file (although it's not terribly rigorous).
Vestigia nulla retrorsum */
static void eraseFile( const STREAM *stream, long position, long length )
{
/* Wipe everything past the current position in the file */
while( length > 0 )
{
RESOURCE_DATA msgData;
BYTE buffer[ BUFSIZ * 2 ];
int bytesToWrite = min( length, BUFSIZ * 2 );
/* We need to make sure that we fill the buffer with random data for
each write, otherwise compressing filesystems will just compress
it to nothing */
setMessageData( &msgData, buffer, bytesToWrite );
krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
if( FSWrite( stream->refNum, &bytesWritten, buffer ) != noErr )
break; /* An error occurred while writing, exit */
length -= bytesToWrite;
}
SetFPos( stream->refNum, fsFromStart, position );
SetEOF( stream->refNum, position );
}
void fileClearToEOF( const STREAM *stream )
{
long eof, position, length;
assert( isReadPtr( stream, sizeof( STREAM ) ) );
assert( stream->type == STREAM_TYPE_FILE );
/* Wipe everything past the current position in the file */
if( GetFPos( stream->refNum, &position ) != noErr || \
GetEOF( stream->refNum, &eof ) != noErr )
return;
length = eof - position;
if( length <= 0 )
return; /* Nothing to do, exit */
eraseFile( stream, position, length );
}
void fileErase( const char *fileName )
{
STREAM stream;
BYTE buffer[ BUFSIZ ];
int length, status;
assert( fileName != NULL );
/* Try and open the file so that we can erase it. If this fails, the
best that we can do is a straight unlink */
status = sFileOpen( &stream, fileName,
FILE_READ | FILE_WRITE | FILE_EXCLUSIVE_ACCESS );
if( cryptStatusError( status ) )
{
remove( fileName );
return;
}
/* Determine the size of the file and erase it */
SetFPos( stream.refNum, fsFromStart, 0 );
GetEOF( stream.refNum, &length );
eraseFile( stream, position, length );
/* Delete the file */
sFileClose( &stream );
FSpDelete( stream.fsspec );
}
/* Build the path to a file in the cryptlib directory */
void fileBuildCryptlibPath( char *path, const char *fileName,
const BOOLEAN createPath )
{
strcpy( path, ":" );
strcat( path, fileName );
strcat( path, ".p15" );
}
/****************************************************************************
* *
* Non-STDIO File Stream Functions *
* *
****************************************************************************/
#elif defined( CONFIG_NO_STDIO )
#if defined( __VMCMS__ ) || defined( __IBM4758__ )
/* Some environments place severe restrictions on what can be done with file
I/O, either having no filesystem at all or having one with characteristics
that don't fit the stdio model. For these systems we used our own in-
memory buffers and make them look like memory streams until they're
flushed, at which point they're written to backing store (flash RAM/
EEPROM/DASD/whatever non-FS storage is being used) in one go.
For streams with the sensitive bit set we don't expand the buffer size
because the original was probably in protected memory, for non-sensitive
streams we expand the size if necessary. This means that we have to
choose a suitably large buffer for sensitive streams (private keys), but
one that isn't too big. 16K is about right, since typical private key
files with cert chains are 2K */
#define STREAM_BUFSIZE 16384
#endif /* __VMCMS__ || __IBM4758__ */
/* Open/close a file stream */
int sFileOpen( STREAM *stream, const char *fileName, const int mode )
{
#ifdef __IBM4758__
const BOOLEAN useBBRAM = ( mode & FILE_SENSITIVE ) ? TRUE : FALSE;
#endif /* __IBM4758__ */
long length, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( fileName != NULL );
assert( mode != 0 );
/* Initialise the stream structure */
memset( stream, 0, sizeof( STREAM ) );
stream->type = STREAM_TYPE_MEMORY;
if( ( mode & FILE_RW_MASK ) == FILE_READ )
stream->flags = STREAM_FLAG_READONLY;
#if defined( __IBM4758__ )
/* Make sure that the filename matches the 4758's data item naming
conventions and remember the filename. The best error code to return
if there's a problem is a file open error, since this is buried so
many levels down that a parameter error won't be meaningful to the
caller */
if( strlen( fileName ) > 8 )
return( CRYPT_ERROR_OPEN );
strcpy( stream->name, fileName );
/* If we're doing a read, fetch the data into memory */
if( mode & FILE_READ )
{
/* Find out how big the data item is and allocate a buffer for
it */
status = sccGetPPDLen( ( char * ) fileName, &length );
if( status != PPDGood )
return( ( status == PPD_NOT_FOUND ) ? CRYPT_ERROR_NOTFOUND : \
( status == PPD_NOT_AUTHORIZED ) ? CRYPT_ERROR_PERMISSION : \
CRYPT_ERROR_OPEN );
if( ( stream->buffer = clAlloc( "sFileOpen", length ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
stream->bufSize = stream->bufEnd = length;
stream->isIOStream = TRUE;
/* Fetch the data into the buffer so it can be read as a memory
stream */
status = sccGetPPD( ( char * ) fileName, stream->buffer, length );
return( ( status != PPDGood ) ? CRYPT_ERROR_READ : CRYPT_OK );
}
/* We're doing a write, make sure that there's enough room available.
This doesn't guarantee that there'll be enough when the data is
committed, but it makes sense to at least check when the "file" is
opened */
status = sccQueryPPDSpace( &length, useBBRAM ? PPD_BBRAM : PPD_FLASH );
if( status != PPDGood || length < STREAM_BUFSIZE )
return( CRYPT_ERROR_OPEN );
/* Allocate the initial I/O buffer for the data */
if( ( stream->buffer = clAlloc( "sFileOpen", STREAM_BUFSIZE ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
stream->bufSize = STREAM_BUFSIZE;
stream->isSensitive = useBBRAM;
return( CRYPT_OK );
#elif defined( __VMCMS__ )
/* If we're going to be doing a write either now or later, we can't open
the file until we have all of the data that we want to write to it
available since the open arg has to include the file format
information, so all we can do at this point is remember the name for
later use */
strcpy( stream->name, fileName );
asciiToEbcdic( stream->name, strlen( stream->name ) );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -