📄 cryptlib.c
字号:
/* If anything failed, shut down the internal functions and services
before we exit */
if( !cryptStatusOK( status ) )
{
if( initLevel >= 3 )
{
/* Shut down any external interfaces after making sure that the
initalisation ran to completion */
waitSemaphore( SEMAPHORE_DRIVERBIND );
dispatchManagementAction( preShutdownFunctions,
MANAGEMENT_ACTION_PRE_SHUTDOWN );
dispatchManagementAction( shutdownFunctions,
MANAGEMENT_ACTION_SHUTDOWN );
}
if( initLevel >= 2 )
destroyObjects();
if( initLevel >= 1 )
endInternalFunctions();
endInitialisation( FALSE );
return( status );
}
/* Unlock the initialisation state */
endInitialisation( TRUE );
return( CRYPT_OK );
}
int endCryptlib( void )
{
int status;
/* If we've already been shut down, don't do anything */
if( !beginInitialisation( FALSE ) )
return( CRYPT_OK );
/* Reverse the process carried out in the multi-phase bootstrap */
waitSemaphore( SEMAPHORE_DRIVERBIND );
dispatchManagementAction( preShutdownFunctions,
MANAGEMENT_ACTION_PRE_SHUTDOWN );
status = destroyObjects();
dispatchManagementAction( shutdownFunctions,
MANAGEMENT_ACTION_SHUTDOWN );
endInternalFunctions();
/* Unlock the initialisation state */
endInitialisation( FALSE );
/* If the Win32 version is being compiled as a static .lib, we need to
perform the cleanup here */
#if defined( __WIN32__ ) && defined( STATIC_LIB )
/* Delete the initialisation lock in the kernel */
postShutdown();
#endif /* __WIN32__ && STATIC_LIB */
return( status );
}
/****************************************************************************
* *
* Client/Server Interface Routines *
* *
****************************************************************************/
/* If we're running in our own address space (either in another VM or on
separate hardware), we need to have some sort of client/server mechanism
to communicate with processes running in the applications address space.
The following section implements the server-side interface for various
environments */
#ifdef USE_CLIENT_SERVER
/* Prototypes for functions in cryptapi.c. Currently this is all done
locally (cryptsvr_client calls cryptsvr_server directly), someone else
can fight with these daemons... */
#if defined( __UNIX__ )
#include <sys/un.h>
#define DAEMON_NAME "cryptd"
#define DAEMON_SOCKET_NAME "/dev/crypt"
#define DAEMON_NO_THREADS 10
/* Per-thread main function */
static MUTEX acceptMutex; /* Mutex for accept() */
static int sockfd; /* Socket for accept() */
static BOOLEAN doShutdown = FALSE; /* Signal for threads to shut down */
static int activeThreads = 0; /* No.of currently active threads */
THREADFUNC_DEFINE( threadedMain, dummy )
{
while( TRUE )
{
int connfd;
/* Some implementations don't handle threads blocking in accept() too
well, and in any case managing the thundering herd in user space
is a lot more efficient than doing it in the kernel, so we
explicitly manage locking ourselves with a mutex.
If we've been told to shut down, we don't try the accept() but
just drop through to the shutdown check afterwards. This
decrements the activeThreads counter, the last thread out turns
off the lights. The way the shutdown works is that the accept()
fails (due to the socket being closed) and the thread falls out of
the accept lock/unlock, at which point either it passes into the
shutdown lock/unlock and exits or (rarely) it gets preempted and
the next thread passes through the accept lock/unlock. In the
most extreme case the accept mutex pileup moves down to the exit
mutex, but in either case all threads eventually terminate. The
only time the daemon might shut down improperly is if a thread is
in the middle of a long-running keygen and keeps everything else
active. There isn't really any clean way to handle this, and in
any case if the system is about to shut down there probably won't
be anything left running to pick up the pieces */
MUTEX_LOCK( &acceptMutex );
if( !doShutdown )
connfd = accept( sockfd, NULL, 0 );
MUTEX_UNLOCK( &acceptMutex );
if( doShutdown )
{
MUTEX_LOCK( &acceptMutex );
activeThreads--;
if( !activeThreads )
cryptEnd();
MUTEX_UNLOCK( &acceptMutex );
THREAD_EXIT();
}
if( connfd == -1 )
{
/* If we got zapped by a signal, continue where we left off */
if( errno == EINTR )
continue;
/* If we got caught by a RST for an established connection before
accept() got called, the connection will be aborted, in which
case we just continue */
if( errno == ECONNABORTED )
continue;
/* ... */
}
/* Get the request type and make sure that it's valid */
/* ... */
/* Dispatch the request */
status = dispatchRequest( request.UserDefined, request.RequestID );
/* Clean up */
close( connfd );
}
}
/* Set up the daemon and fire up the thread pool */
void sigTermFunction( int dummy )
{
/* Signal all active threads to die and close the socket, which forces
accept() to fail, guaranteeing that a thread doesn't remain blocked
in the call */
doShutdown = TRUE;
close( socket );
}
int main( int argc, char *argv[] )
{
THREAD threadPool[ DAEMON_NO_THREADS ];
const struct rlimit rl = { 0, 0 };
struct sockaddr_un sockAddr;
struct timeval tv;
char *socketName, *errorString = NULL;
int fd, status;
/* Start logging our status */
openlog( DAEMON_NAME, 0, LOG_DAEMON );
syslog( LOG_INFO, DAEMON_NAME "started" );
/* Check that everything is OK */
if( argc > 2 )
errorString = "usage: " DAEMON_NAME " <server socket pathname>";
else
{
socketName = ( argc == 2 ) ? argv[ 1 ] : DAEMON_SOCKET_NAME;
if( strlen( socketName > 100 )
errorString = DAEMON_NAME ": Socket pathname too long";
else
if( access( socketName, F_OK )
errorString = DAEMON_NAME ": Socket already exists";
}
if( errorString != NULL )
{
syslog( LOG_ERR, errorString );
closelog();
exit( EXIT_FAILURE );
}
/* Turn ourselves into a daemon by forking a new process and killing its
parent. After this sequence of operations, we're a daemon owned by
init */
if( ( status = fork() ) < 0 )
{
syslog( LOG_ERR, "%m" );
closelog();
exit( EXIT_FAILURE );
}
if( status )
exit( EXIT_SUCCESS ); /* Exit if we're the parent */
#if 1
/* Create a new session with ourselves as the session leader and no
controlling TTY, ignore SIGHUP, and fork again. This is necessary
because when a session leader without a controlling terminal opens a
terminal device, it gets assigned as its controlling TTY. By forking
a second time, we make sure that the child is no longer a session
leader. The reason we need to ignore SIGHUP is because when the
first-level child (the session leader) exits, the second-level child
(just another process in the session) will be SIGHUP'd */
setsid();
signal( SIGHUP, SIG_IGN );
if( ( status = fork() ) != 0 )
exit( EXIT_SUCCESS );
#else
/* Detach ourselves from the controlling TTY to avoid interruptions and
move into our own process group to avoid mass murders */
fd = open( "/dev/tty", O_RDWR );
ioctl( fd, TIOCNOTTY, 0 );
close( fd );
setpgrp( 0, getpid() );
#endif /* 1 */
/* Close all inherited file descriptors */
for( fd = getdtablesize() - 1; fd >= 0; fd-- )
close( fd );
/* Move to a (safe) standard directory, set our umask to make sure that
our files are kept private (although the cryptlib streams module does
this anyway), and point the stdin, stdout, and stderr streams to the
null device in case library routines try and do any I/O */
chdir( "/tmp" );
umask( 0177 ); /* Owner RW access only */
fd = open( "/dev/null", O_RDWR ); /* stdin = 0 */
dup( fd ); /* stdout = 1 */
dup( fd ); /* stderr = 2 */
/* Make sure that we can never dump core (we really, *really* don't want
to do this) */
setrlimit( RLIMIT_CORE, &rl );
/* Go catatonic */
signal( SIG_IGN, SIGHUP );
/* Create a domain socket and wait for connections */
memset( sockAddr, 0, sizeof( struct sockaddr_un ) );
strcpy( sockAddr.sun_path, socketName );
status = sockfd = socket( AF_LOCAL, SOCK_STREAM, 0 );
if( status != -1 )
status = bind( sockfd, ( SA * ) &sockAddr, SUN_LEN( &sockAddr ) );
if( status != -1 )
status = listen( sockfd, 5 );
if( status == -1 )
{
syslog( LOG_ERR, "%m" );
closelog();
exit( EXIT_FAILURE );
}
/* Set the socket timeout to 5 seconds to make sure that we don't block
forever if a client hangs */
tv.tv_sec = 5;
tv.tv_usec = 0;
setsockopt( sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv,
sizeof( struct timeval ) );
setsockopt( sockfd, SOL_SOCKET, SO_SNDTIMEO, &tv,
sizeof( struct timeval ) );
/* Initialise the crypto code */
status = cryptInit();
if( cryptStatusError( status ) )
{
syslog( LOG_ERR, "Crypto initialisation failed" );
closelog();
exit( EXIT_FAILURE );
}
/* Make sure that if we get killed by init, we shut down cleanly */
signal( sigTermFunction, SIGTERM );
/* Start up the thread pool. We hold the accept() mutex while we're
doing this to ensure that it's an all-or-nothing start, in other
words that there are no threads accepting commands while there's
still a chance that the init could be aborted */
MUTEX_INIT( &acceptMutex );
MUTEX_LOCK( &acceptMutex );
for( i = 0; i < DAEMON_NO_THREADS; i++ )
{
status = THREAD_CREATE( &threadMain, NULL );
if( THREAD_STATUS( status ) != CRYPT_OK )
break;
activeThreads++;
}
if( cryptStatusError( status ) )
{
/* Signal any threads that got started to terminate immediately */
doShutdown = TRUE;
close( socket );
MUTEX_UNLOCK( &acceptMutex );
syslog( LOG_ERR, "Thread pool initialisation failed" );
closelog();
exit( EXIT_FAILURE );
}
MUTEX_UNLOCK( &acceptMutex );
/* We're ready to talk, make the socket path accessible to others (the
umask will have made it inaccessible, which is fine since we don't
want anyone poking messages at us while we're initialising) */
chmod( socketName, 0666 );
/* Everything is done by the threads, so we just twiddle our thumbs */
while( TRUE )
pause();
/* Clean up */
MUTEX_DESTROY( &acceptMutex );
exit( EXIT_SUCCESS );
}
#elif defined( __WINDOWS__ )
#define SERVICE_NAME "cryptd"
#define SERVICE_DISPLAY_NAME "cryptlib Server"
#define SERVICE_PATH "%SystemRoot%\\System32\\cryptd.exe"
SERVICE_STATUS serviceStatus;
SERVICE_STATUS_HANDLE hServiceStatus;
/* Service control handler */
void WINAPI Handler( DWORD fdwControl )
{
switch( fdwControl )
{
case SERVICE_CONTROL_STOP:
serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
break;
case SERVICE_CONTROL_SHUTDOWN:
break;
case SERVICE_CONTROL_INTERROGATE:
; /* Fall through */
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -