Mercurial > illumos > illumos-gate
diff usr/src/lib/libkmsagent/common/SYSCommon.c @ 12720:3db6e0082404
PSARC 2010/195 PKCS11 KMS Provider
6944296 Solaris needs a PKCS#11 provider to allow access to KMS keystore functionality
author | Wyllys Ingersoll <Wyllys.Ingersoll@Sun.COM> |
---|---|
date | Mon, 28 Jun 2010 16:04:11 -0700 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libkmsagent/common/SYSCommon.c Mon Jun 28 16:04:11 2010 -0700 @@ -0,0 +1,2307 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +/*--------------------------------------------------------------------------- + * Module: SYSCommon.c + *-------------------------------------------------------------------------*/ + +#include <stdio.h> +#include "SYSCommon.h" +#include <time.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <signal.h> + +#ifndef WIN32 +#include <unistd.h> +#endif + +#ifdef WIN32 +#include <io.h> +#include <stdlib.h> /* for malloc, calloc, and free */ +#elif defined K_LINUX_PLATFORM +#include <unistd.h> /* it includes usleep(us) */ +#include <sys/time.h> +#include <fts.h> +#else +/* + * Directory traversal code is not yet available for Solaris. + * If such code will need to be written, then it will probably use ftw.h. + */ +#endif + +#ifdef K_SOLARIS_PLATFORM +/* For K_AdjustLocalClock */ +#include <unistd.h> +/* For K_SetRootPassword */ +#define __EXTENSIONS__ /* to expose flockfile and friends in stdio.h */ +#include <errno.h> +#include <libgen.h> +#include <malloc.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <strings.h> +#include <stropts.h> +#include <unistd.h> +#include <termio.h> +#include <security/pam_appl.h> +#include <widec.h> +#endif + +#ifdef K_LINUX_PLATFORM +extern int pthread_mutexattr_settype __P ((pthread_mutexattr_t *__attr, + int __kind)); +#endif + +#ifdef K_HPUX_PLATFORM +int64 atoll(const char *str) +{ + int64 tmp = 0; + sscanf(str, "%lld", &tmp); + return tmp; +} + +#endif + + +/*--------------------------------------------------------------------------- + * Function: K_CreateThread + * + * Description: + * Thread creation function "CreateThread" takes a thread function + * and its parameter to create a thread. It also has a Boolean + * parameter to indicate if the thread is detached or joinable. + * A new thread's handle is returned through the output parameter. + * + * Input + * ----- + * i_pFunc Function pointer of the thread function + * i_pvData The point of the parameter passed to the thread function + * i_bIsDetached The thread is detached or not + * (Note: It is not supported on Win32) + * + * Output + * ------ + * o_pNewThread The Thread handle + * + * Return value Error code + * + *--------------------------------------------------------------------------*/ + +int K_CreateThread(K_ThreadFunc i_pFunc, + void *i_pvData, + int i_bIsDetached, + K_THREAD_HANDLE *o_pNewThread) +{ + int iOK = K_SYS_OK; + int iReturn = 0; + +#ifdef WIN32 + + { + unsigned id; + + *o_pNewThread = (HANDLE)_beginthreadex(NULL, + 0, + (int (_stdcall *) (void *vpData))i_pFunc, + i_pvData, + 0, + &id); + + + if(*o_pNewThread == 0) + { +#ifdef SYS_DEBUG + printf(" (%s, %d): error creating pthread, error = %d\n", + __FILE__, __LINE__, iReturn); +#endif + return K_SYS_ERR_CREATE_THREAD; + } + + return K_SYS_OK; + } + +#else + pthread_attr_t attr; + + iReturn = pthread_attr_init(&attr); + + if ( iReturn == 0 ) + { + iReturn = pthread_attr_setdetachstate(&attr, (i_bIsDetached) ? + PTHREAD_CREATE_DETACHED : + PTHREAD_CREATE_JOINABLE); + } + +#ifdef UNIX + if ( iReturn == 0 ) + { + iReturn = pthread_attr_setstacksize(&attr, 1024*1024); + } +#endif + + if ( iReturn == 0 ) + { + iReturn = pthread_create(o_pNewThread, &attr, (void *(*)(void *)) i_pFunc, i_pvData); + } + + if ( iReturn == 0 ) + { + iReturn = pthread_attr_destroy(&attr); + } + + // TODO: Log error? + if ( iReturn ) + { +#ifdef SYS_DEBUG + printf(" (%s, %d): error creating pthread, error = %d\n", + __FILE__, __LINE__, iReturn); +#endif + + iOK = K_SYS_ERR_CREATE_THREAD; + } + + return iOK; +#endif +} + + +/*--------------------------------------------------------------------------- + * Function: K_JoinThread + * + * Description: + * Thread joining function is called when the current thread + * waits another thread to terminate. + * + * Input + * ----- + * i_hThread The thread handle of the to-be-joined thread + * + * Output + * ------ + * (none) + * + * Return value Error code + * + *--------------------------------------------------------------------------*/ + +int K_JoinThread(K_THREAD_HANDLE i_hThread) +{ + int iOK = K_SYS_OK; +#ifdef WIN32 + + WaitForSingleObject(i_hThread, INFINITE); + +#else + { + int iReturn; + iReturn = pthread_join(i_hThread, NULL); + + if ( iReturn ) + { + +#ifdef SYS_DEBUG + printf(" (%s, %d): error creating pthread, error = %d\n", + __FILE__, __LINE__, iReturn); +#endif + iOK = K_SYS_ERR_JOIN_THREAD; + } + } + +#endif + return iOK; +} + + +/*--------------------------------------------------------------------------- + * Function: K_GetCurrentThreadId + * + * Description: + * Returns the thread ID of the current thread. + * + * Input + * ----- + * (none) + * + * Output + * ------ + * (none) + * + * Return value The thread ID + * + *--------------------------------------------------------------------------*/ + +int K_GetCurrentThreadId() +{ +#ifdef WIN32 + return GetCurrentThreadId(); +#else + return pthread_self(); +#endif + +} + + +/*--------------------------------------------------------------------------- + * Function: K_CreateMutex + * + * Description: + * The mutex creation function creates a mutex according to the given + * mutex type, and returns the mutex handle to the output parameter. + * + * Input + * ----- + * i_bIsRecursive Indication whether the mutex can be entered recursively + * + * Output + * ------ + * o_phandle the handle pointer to the mutex + * + * Return value Error Code + * + *--------------------------------------------------------------------------*/ + +int K_CreateMutex( K_MUTEX_HANDLE *o_phandle ) +{ + int iOK = K_SYS_OK; + BOOL bIsRecursive = 1; // this used to be an input -- but why do we want this to be optional? + +#ifdef WIN32 + { + *o_phandle = (WIN32Mutex *)malloc(sizeof(WIN32Mutex)); + if(*o_phandle == NULL) + { + return K_SYS_ERR_NO_MEMORY; + } + (*o_phandle)->m_bIsRecursive = bIsRecursive; + if(bIsRecursive) + { + InitializeCriticalSection(&((*o_phandle)->m_stCriticalSection)); + } + else + { + (*o_phandle)->m_handle = CreateMutex(NULL, FALSE, NULL); + } + + } +#else + { + int iType; + pthread_mutexattr_t attr; + + if ( pthread_mutexattr_init(&attr) ) + { + return K_SYS_ERR_COND; + } + + if(bIsRecursive) + { + iType = +#ifdef K_LINUX_PLATFORM + PTHREAD_MUTEX_RECURSIVE_NP; +#else + PTHREAD_MUTEX_RECURSIVE; +#endif + + if ( pthread_mutexattr_settype(&attr, iType) ) + { + return K_SYS_ERR_COND; + } + } + + *o_phandle = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t)); + if(*o_phandle == NULL) + { + return K_SYS_ERR_NO_MEMORY; + } + + if ( pthread_mutex_init(*o_phandle, &attr) ) + { + return K_SYS_ERR_COND; + } + + if ( pthread_mutexattr_destroy(&attr) ) + { + return K_SYS_ERR_COND; + } + } +#endif + + return iOK; +} + + +/*--------------------------------------------------------------------------- + * Function: K_LockMutex + * + * Description: + * K_LockMutex is used to lock the mutex, and K_UnlockMutex is + * used to unlock it. + * + * Input + * ----- + * i_handle the mutex handle + * + * Output + * ------ + * (none) + * + * Return value Error Code + * + *--------------------------------------------------------------------------*/ + +int K_LockMutex(K_MUTEX_HANDLE i_handle) +{ + int iOK = K_SYS_OK; +#ifdef WIN32 + + if(i_handle->m_bIsRecursive) + { + EnterCriticalSection(&(i_handle->m_stCriticalSection)); + } + else + { + WaitForSingleObject(i_handle->m_handle, INFINITE); + } + +#else + + if ( pthread_mutex_lock(i_handle) ) + { + return K_SYS_ERR_COND; + } + +#endif + return iOK; // TODO: better error handling +} + + +/*--------------------------------------------------------------------------- + * Function: K_UnlockMutex + * + * Description: + * K_UnlockMutex is used to unlock the lock. + * + * Input + * ----- + * i_handle the mutex handle + * + * Output + * ------ + * (none) + * + * Return value Error Code + * + *--------------------------------------------------------------------------*/ + +int K_UnlockMutex(K_MUTEX_HANDLE i_handle) +{ + int iOK = K_SYS_OK; + +#ifdef WIN32 + if(i_handle->m_bIsRecursive) + { + LeaveCriticalSection(&(i_handle->m_stCriticalSection)); + } + else + { + ReleaseMutex(i_handle->m_handle); + } + +#else + + if ( pthread_mutex_unlock(i_handle) ) + { + return K_SYS_ERR_COND; + } +#endif + + return iOK; // TODO: better error handling +} + + +/*--------------------------------------------------------------------------- + * Function: K_DestroyMutex + * + * Description: + * When a mutex is no longer needed, K_DestroyMutex must be called + * to destroy it. + * + * Input + * ----- + * i_handle the mutex handle + * Output + * ------ + * (none) + * + * Return value Error Code + * + *--------------------------------------------------------------------------*/ + +int K_DestroyMutex(K_MUTEX_HANDLE i_handle) +{ + + int iOK = K_SYS_OK; + +#ifdef WIN32 + + if(i_handle->m_bIsRecursive) + { + DeleteCriticalSection(&(i_handle->m_stCriticalSection)); + } + else + { + CloseHandle(i_handle->m_handle); + } + free(i_handle); + +#else + pthread_mutex_destroy(i_handle); + free(i_handle); +#endif + return iOK; // TODO: better error handling +} + + +/*--------------------------------------------------------------------------- + * Function: K_InitConditionalVariable + * + * Description: + * This function initializes a conditional variable. Upon successful + * completion, the new condition variable is returned via the condition + * parameter, and 0 is returned. Otherwise, an error code is returned. + * + * Input + * ----- + * i_pCond the pointer to the conditional variable which is to be + * initialized + * + * Output + * ------ + * (none) + * + * Return value Error Code + * + *--------------------------------------------------------------------------*/ + +int K_InitConditionalVariable (K_ConditionalVariable * i_pCond) +{ + int iOK = K_SYS_OK; +#ifdef WIN32 + + i_pCond->m_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + i_pCond->m_hMutex = CreateMutex(NULL, FALSE, NULL); + i_pCond->m_iSignalAll = 0; + i_pCond->m_iNumWaiting = 0; + +#else + + if ( pthread_cond_init(i_pCond, NULL) ) + { + return K_SYS_ERR_COND; + } + +#endif + + return iOK; +} + + +/*--------------------------------------------------------------------------- + * Function: K_DestroyConditionalVariable + * + * Description: + * This function destroys a conditional variable. Upon successful + * completion, the condition variable is destroyed, and 0 is returned. + * Otherwise, an error code is returned. + * After deletion of the condition variable, the condition parameter + * is not valid until it is initialized again by a call to the + * K_InitConditionalVariable subroutine. + * + * Input + * ----- + * i_pCond the pointer to the conditional variable which is to be + * destroyed + * Output + * ------ + * (none) + * + * Return value Error Code + * + *--------------------------------------------------------------------------*/ + +int K_DestroyConditionalVariable(K_ConditionalVariable * i_pCond) +{ + int iOK = K_SYS_OK; +#ifdef WIN32 + CloseHandle(i_pCond->m_hMutex); + CloseHandle(i_pCond->m_hEvent); +#else + + if ( pthread_cond_destroy(i_pCond) ) + { + return K_SYS_ERR_COND; + } + +#endif + return iOK; + +} + + +/*--------------------------------------------------------------------------- + * Function: K_WaitConditionalVariable + * + * Description: + * This function is used to block on a condition variable. + * They are called with mutex locked by the calling thread or undefined + * behaviour will result. + * + * Input + * ----- + * i_pCond the pointer to the conditional variable + * i_handle the companion mutex handle + * + * Output + * ------ + * (none) + * + * Return value Error Code + * + *--------------------------------------------------------------------------*/ + +int K_WaitConditionalVariable(K_ConditionalVariable * i_pCond, + K_MUTEX_HANDLE i_handle) +{ + + int iOK = K_SYS_OK; +#ifdef WIN32 + DWORD res; + + while (1) + { + iOK = WaitForSingleObject(i_pCond->m_hMutex, INFINITE); + if (iOK != WAIT_OBJECT_0) + { + return K_SYS_ERR_COND; + } + i_pCond->m_iNumWaiting++; + ReleaseMutex(i_pCond->m_hMutex); + + K_UnlockMutex(i_handle); + res = WaitForSingleObject(i_pCond->m_hEvent, INFINITE); + i_pCond->m_iNumWaiting--; + + if (res != WAIT_OBJECT_0) + { + ReleaseMutex(i_pCond->m_hMutex); + return K_SYS_ERR_COND; + } + + if (i_pCond->m_iSignalAll) + { + if (i_pCond->m_iNumWaiting == 0) + { + ResetEvent(i_pCond->m_hEvent); + } + break; + } + + if (i_pCond->m_iSignalled) + { + i_pCond->m_iSignalled = 0; + ResetEvent(i_pCond->m_hEvent); + break; + } + ReleaseMutex(i_pCond->m_hMutex); + } + + K_LockMutex(i_handle); + + return K_SYS_OK; +#else + + if ( pthread_cond_wait(i_pCond, i_handle) ) + { + return K_SYS_ERR_COND; + } + +#endif + return iOK; // TODO: better error handling +} + + +/*--------------------------------------------------------------------------- + * Function: K_SignalConditionalVariable + * + * Description: + * This function is used to restart one of the threads that are waiting on + * the condition variable. If no threads are waiting on it, nothing happens. + * If several threads are waiting on it, exactly one is restarted. + * + * Input + * ----- + * i_pCond the pointer to the conditional variable + * + * Output + * ------ + * (none) + * + * Return value Error Code + * + *--------------------------------------------------------------------------*/ + +int K_SignalConditionalVariable(K_ConditionalVariable * i_pCond) +{ + int iOK = K_SYS_OK; +#ifdef WIN32 + + int iReturn; + + iReturn = WaitForSingleObject(i_pCond->m_hMutex, INFINITE); + if (iReturn != WAIT_OBJECT_0) + { + return K_SYS_ERR_COND; + } + + i_pCond->m_iSignalled = 1; + + iReturn = SetEvent(i_pCond->m_hEvent); + if (iReturn == 0) + { + iOK = K_SYS_ERR_COND; + } + ReleaseMutex(i_pCond->m_hMutex); + + return iOK; +#else + + if ( pthread_cond_signal(i_pCond) ) + { + return K_SYS_ERR_COND; + } + +#endif + return iOK; +} + + +/*--------------------------------------------------------------------------- + * Function: K_BroadcastConditionalVariable + * + * Description: + * This function is used to restart all threads that are waiting on + * the condition variable. + * + * Input + * ----- + * i_pCond the pointer to the conditional variable + * + * Output + * ------ + * (none) + * + * Return value Error Code + * + *--------------------------------------------------------------------------*/ + +int K_BroadcastConditionalVariable(K_ConditionalVariable * i_pCond) +{ + + int iOK = K_SYS_OK; + +#ifdef WIN32 + + int iReturn; + + iReturn = WaitForSingleObject(i_pCond->m_hMutex, INFINITE); + if (iReturn != WAIT_OBJECT_0) + { + return K_SYS_ERR_COND; + } + i_pCond->m_iSignalled = 1; + i_pCond->m_iSignalAll = 1; + + iReturn = SetEvent(i_pCond->m_hEvent); + + if (iReturn == 0) + { + iOK = K_SYS_ERR_COND; + } + + ReleaseMutex(i_pCond->m_hMutex); + + return iOK; + +#else + + if ( pthread_cond_broadcast(i_pCond) ) + { + return K_SYS_ERR_COND; + } + +#endif + return iOK; +} + + +/*--------------------------------------------------------------------------- + * Function: K_Sleep + * + * Description: + * Sleep for a given period in given milliseconds. + * + * Input + * ----- + * i_ms milliseconds + * + * Output + * ------ + * (none) + * + * Return value (none) + * + *--------------------------------------------------------------------------*/ + +void K_Sleep(int i_ms) +{ +#ifdef WIN32 + Sleep(i_ms); +#else + usleep(i_ms * 1000); +#endif +} + + +/*--------------------------------------------------------------------------- + * Function: K_GetTickCount + * + * Description: + * The K_GetTickCount function retrieves the number of + * milliseconds that have elapsed since the system was started. + * + * Input + * ----- + * (none) + * + * Output + * ------ + * (none) + * + * Return value the elasped milliseconds since the system was started + * + *--------------------------------------------------------------------------*/ + +unsigned int K_GetTickCount() +{ +#ifdef WIN32 + return (unsigned int)GetTickCount(); +#else + { + struct timeval tv; + gettimeofday( &tv, NULL ); + /* this will rollover ~ every 49.7 days + dont surprise when it returns negative values, since we are only interested + in using sth like "tickCount2 - tickCount1" to get the time interval + */ + return ( tv.tv_sec * 1000 ) + ( tv.tv_usec / 1000 ); + } +#endif +} + + +/*--------------------------------------------------------------------------- + * Function: K_AdjustClock + * + * Description: + * The K_AdjustClock function immediately adjusts the system clock by + * the given number of seconds. A positive number adjusts the system + * clock forward; a negative number adjusts the system clock backward. + * + * Input + * ----- + * i_iAdjustmentInSeconds Number of seconds by which to adjust the + * system clock + * Output + * ------ + * (none) + * + * Return value 1 if successful, 0 on error + * + *--------------------------------------------------------------------------*/ + +int K_AdjustClock( long i_iAdjustmentInSeconds ) +{ +#ifndef WIN32 + struct timeval stDateTime; + if ( 0 != gettimeofday(&stDateTime, NULL) ) + { + return FALSE; + } + + stDateTime.tv_sec += i_iAdjustmentInSeconds; + + if ( 0 != settimeofday(&stDateTime, NULL) ) + { + return FALSE; + } +#else + // TODO: implement for Windows + return FALSE; +#endif + + return TRUE; +} + + +/*--------------------------------------------------------------------------- + * Function: K_IsLittleEndian + * + * Description: + * Checks to see whether this platform uses little endian integer + * representation. + * + * Input + * ----- + * (none) + * + * Output + * ------ + * (none) + * + * Return value 1 for little endian + * + *--------------------------------------------------------------------------*/ + +int K_IsLittleEndian() +{ + short iWord = 0x4321; + return ((*(unsigned char*)&iWord) == 0x21); +} + + +/*--------------------------------------------------------------------------- + * Function: K_FileLength32 + * + * Description: + * Gets the size in bytes of the file associated with the given FILE pointer. + * + * Input + * ----- + * i_fpFile File handle + * + * Output + * ------ + * (none) + * + * Return value File size in bytes, or -1L on error + * + *--------------------------------------------------------------------------*/ + +long K_FileLength32( FILE* i_fpFile ) +{ +#ifdef WIN32 + int iFileDescriptor = _fileno( i_fpFile ); + struct _stat stStat; + + if ( _fstat(iFileDescriptor, &stStat) != 0) + { + // error + return -1L; + } + +#else + int iFileDescriptor = fileno( i_fpFile ); + struct stat stStat; + + if ( fstat(iFileDescriptor, &stStat) != 0) + { + // error + return -1L; + } + +#endif + + return stStat.st_size; +} + + +/*--------------------------------------------------------------------------- + * Function: K_StringCompareNoCase + * + * Description: + * Compares the two given strings insensitive to case. + * + * Input + * ----- + * i_sString1 First string + * i_sString2 Second string + * + * Output + * ------ + * (none) + * + * Return value 0 if identical, -1 if first string is less than second + * string, or 1 if first string is greater than second + * + *--------------------------------------------------------------------------*/ + +int K_StringCompareNoCase( const char* i_sString1, const char* i_sString2 ) +{ +#ifdef WIN32 + return _stricmp( i_sString1, i_sString2 ); +#else + return strcasecmp( i_sString1, i_sString2 ); +#endif +} + + +/*--------------------------------------------------------------------------- + * Function: K_StringCompareNoCaseWide + * + * Description: + * Compares the two given wide strings insensitive to case. + * + * Input + * ----- + * i_wsString1 First wide string + * i_wsString2 Second wide string + * + * Output + * ------ + * (none) + * + * Return value 0 if identical, -1 if first string is less than second + * string, or 1 if first string is greater than second + * + *--------------------------------------------------------------------------*/ + +int K_StringCompareNoCaseWide( const wchar_t* i_wsString1, const wchar_t* i_wsString2 ) +{ +#ifdef WIN32 + return _wcsicmp( i_wsString1, i_wsString2 ); +#elif defined K_SOLARIS_PLATFORM + return wscasecmp( i_wsString1, i_wsString2 ); +#else + return wcscasecmp( i_wsString1, i_wsString2 ); +#endif +} + + +/*--------------------------------------------------------------------------- + * Function: K_CreateDirectory + * + * Description: + * Creates a directory with the given path name. + * + * Input + * ----- + * i_sDirectoryName Directory name + * + * Output + * ------ + * (none) + * + * Return value 0 on success, -1 on failure + * + *--------------------------------------------------------------------------*/ + +int K_CreateDirectory( const char* i_sDirectoryName ) +{ + // TODO: make this build all parent directories as well. + +#ifdef WIN32 + if ( CreateDirectoryA( i_sDirectoryName, NULL ) ) + { + return 0; + } + else + { + DWORD dwError = GetLastError(); + return ( dwError == ERROR_ALREADY_EXISTS ) ? 0 : (dwError ? dwError : -1); + } +#else + if ( mkdir( i_sDirectoryName, S_IRWXU ) == 0 ) + { + return 0; + } + else + { + return ( errno == EEXIST ) ? 0 : (errno ? errno : -1); + } +#endif +} + + +/*--------------------------------------------------------------------------- + * Function: K_DeleteFile + * + * Description: + * Deletes the given file. + * + * Input + * ----- + * i_sFilename Name of file to delete + * + * Output + * ------ + * (none) + * + * Return value 0 on success, errno on failure + * + *--------------------------------------------------------------------------*/ + +int K_DeleteFile( const char* i_sFilename ) +{ + int bSuccess = 0; + + bSuccess = +#ifdef WIN32 + _unlink( +#else + unlink( +#endif + i_sFilename ) == 0; + + return bSuccess ? 0 : errno; +} + + +/*--------------------------------------------------------------------------- + * Function: K_ReadFile + * + * Description: + * Reads from the given file and passes the bytes read back to the output + * parameter. The caller must deallocate o_ppFileData using free(). + * + * Input + * ----- + * i_sFilename Name of file from which to read + * + * Output + * ------ + * o_ppFileData Pointer to bytes read + * + * Return value Number of bytes read on success, -1 on failure + * + *--------------------------------------------------------------------------*/ + +int K_ReadFile( const char* i_sFilename, unsigned char** o_ppFileData ) +{ + FILE* pFile = 0; + long iFileSize = 0; + + if ( !i_sFilename || (strlen(i_sFilename) <= 0) || !o_ppFileData ) + { + return -1; + } + + *o_ppFileData = 0; + + // Open the file + + pFile = fopen( i_sFilename, "rb" ); + if ( !pFile ) + { + return -1; + } + + // Determine the file size + + if ( fseek( pFile, 0, SEEK_END ) ) + { + (void) fclose( pFile ); + return -1; + } + + iFileSize = ftell( pFile ); + if ( iFileSize < 0 ) + { + (void) fclose( pFile ); + return -1; + } + else if ( iFileSize == 0 ) + { + (void) fclose( pFile ); + return 0; + } + + if ( fseek( pFile, 0, SEEK_SET ) ) + { + (void) fclose( pFile ); + return -1; + } + + *o_ppFileData = (unsigned char*)malloc( iFileSize ); + if ( !*o_ppFileData ) + { + // Out of memory. + (void) fclose( pFile ); + return -1; + } + + if ( iFileSize != (long)fread( *o_ppFileData, 1, iFileSize, pFile ) ) + { + free( *o_ppFileData ); + *o_ppFileData = 0; + (void) fclose( pFile ); + return -1; + } + + (void) fclose( pFile ); + + return iFileSize; +} + + +/*--------------------------------------------------------------------------- + * Function: K_ReadFileString + * + * Description: + * Reads from the given file and passes the bytes read back to the output + * parameter, appending these bytes with a null terminator. There is no + * guarantee that there are no non-text characters in the returned "string". + * The caller must deallocate o_ppFileData using free(). + * + * Input + * ----- + * i_sFilename Name of file from which to read + * + * Output + * ------ + * o_psFileDataString Pointer to bytes read + * + * Return value Number of bytes read (including null terminator) on + * success (0 if file is empty), -1 on failure + * + *--------------------------------------------------------------------------*/ + +int K_ReadFileString( const char* i_sFilename, char** o_psFileDataString ) +{ + unsigned char* pFileData = 0; + int iFileSize = 0; + + *o_psFileDataString = 0; + + iFileSize = K_ReadFile( i_sFilename, &pFileData ); + + if ( iFileSize <= 0 ) + { + return iFileSize; + } + + *o_psFileDataString = (char*)malloc( iFileSize+1 ); + + if ( !*o_psFileDataString ) + { + // Out of memory. + if ( pFileData ) + { + free( pFileData ); + } + return -1; + } + + memcpy( *o_psFileDataString, pFileData, iFileSize ); + + (*o_psFileDataString)[iFileSize] = '\0'; + + if ( pFileData ) + { + free( pFileData ); + } + + return iFileSize+1; +} + + +/*--------------------------------------------------------------------------- + * Function: K_WriteFile + * + * Description: + * Writes the given bytes to the given file. + * + * Input + * ----- + * i_sFilename Name of file to which to write + * i_pFileData Bytes to write + * i_iFileDataSize Number of bytes to write + * + * Output + * ------ + * (none) + * + * Return value 0 on success, errno or -1 (generic error) on failure + * + *--------------------------------------------------------------------------*/ + +int K_WriteFile( const char* i_sFilename, const unsigned char* i_pFileData, int i_iFileDataSize ) +{ + FILE* pFile = 0; + + if ( !i_sFilename || (strlen(i_sFilename) <= 0) || (!i_pFileData && (i_iFileDataSize > 0)) || (i_iFileDataSize < 0) ) + { + return -1; + } + + pFile = fopen( i_sFilename, "wb" ); + if ( !pFile ) + { + int iError = errno; + return (iError != 0) ? iError : -1; + } + + if ( i_iFileDataSize > 0 ) + { + if ( i_iFileDataSize != (int)fwrite( i_pFileData, 1, i_iFileDataSize, pFile ) ) + { + int iError = ferror( pFile ); + (void) fclose( pFile ); + return (iError != 0) ? iError : -1; + } + } + + (void) fclose( pFile ); + + return 0; +} + + +/*--------------------------------------------------------------------------- + * Function: K_WriteFileString + * + * Description: + * Writes the given null-terminated bytes to the given file. The null + * terminator itself is not written to the file. + * + * Input + * ----- + * i_sFilename Name of file to which to write + * i_sFileData Bytes to write + * + * Output + * ------ + * (none) + * + * Return value 0 on success, errno or -1 (generic error) on failure + * + *--------------------------------------------------------------------------*/ + +int K_WriteFileString( const char* i_sFilename, const char* i_sFileData ) +{ + if ( !i_sFilename || (strlen(i_sFilename) <= 0) || !i_sFileData || (strlen(i_sFileData) <= 0) ) + { + return -1; + } + + return K_WriteFile( i_sFilename, (const unsigned char*)i_sFileData, strlen(i_sFileData) ); +} + + +/*--------------------------------------------------------------------------- + * Function: K_FileExists + * + * Description: + * Checks to see whehter the given file exists. + * + * Input + * ----- + * i_sFilename Name of file to check + * + * Output + * ------ + * (none) + * + * Return value 1 if file exists, 0 if not, -1 on failure + * + *--------------------------------------------------------------------------*/ + +int K_FileExists( const char* i_sFilename ) +{ + FILE* pFile = 0; + + if ( !i_sFilename || (strlen(i_sFilename) <= 0) ) + { + return -1; + } + + pFile = fopen( i_sFilename, "r+" ); + + if ( !pFile ) + { + if ( errno == ENOENT ) + { + return 0; + } + + return -1; + } + + (void) fclose( pFile ); + + return 1; +} + + +/*--------------------------------------------------------------------------- + * Function: K_CopyFile + * + * Description: + * Reads from the given source file and writes these bytes to the given + * destination file. + * + * Input + * ----- + * i_sSrcFilename Name of file from which to read + * i_sDestFilename Name of file to which to write + * + * Output + * ------ + * o_pbFileExists Non-zero if the destination file already exists + * + * Return value 0 on success, errno or -1 (generic error) on failure + * + *--------------------------------------------------------------------------*/ + +int K_CopyFile( const char* i_sSrcFilename, const char* i_sDestFilename, int* o_pbFileExists ) +{ + unsigned char* pFileData = 0; + int iFileSize = 0; + int iError, iFileExists; + + if ( !i_sSrcFilename || (strlen(i_sSrcFilename) <= 0) + || !i_sDestFilename || (strlen(i_sDestFilename) <= 0) + || !o_pbFileExists ) + { + return -1; + } + + *o_pbFileExists = 0; + + iFileExists = K_FileExists( i_sDestFilename ); + + if ( iFileExists < 0 ) + { + iError = errno; + return (iError == 0) ? -1 : iError; + } + else if ( iFileExists > 0 ) + { + *o_pbFileExists = 1; + return -1; + } + + iFileSize = K_ReadFile( i_sSrcFilename, &pFileData ); + if ( iFileSize < 0 ) + { + iError = errno; + return (iError == 0) ? -1 : iError; + } + + iError = K_WriteFile( i_sDestFilename, pFileData, iFileSize ); + + if ( pFileData ) + { + free( pFileData ); + } + + return iError; +} + + +#ifdef K_LINUX_PLATFORM +static int fts_compare( const FTSENT** i_ppF1, const FTSENT** i_ppF2 ) +{ + return strcmp( (*i_ppF1)->fts_name, (*i_ppF2)->fts_name ); +} +#else +/* + * Directory traversal code is not yet available for Solaris. + * If such code will need to be written, then it will probably use ftw.h. + */ +#endif + + +/* + * TODO: Set up functions for platform-specific find-file operations to + * help clean up the code below. + */ + +typedef struct K_FindInfo +{ +#ifdef WIN32 + struct _finddata_t m_stFindData; + long m_hFile; +#elif defined K_LINUX_PLATFORM + FTS* m_pFTS; + FTSENT* m_pFTSENT; +#else +/* + * Directory traversal code is not yet available for Solaris. + * If such code will need to be written, then it will probably use ftw.h. + */ + int unused; +#endif +} K_FindInfo; + +// Memory for filename is held in i_pFindInfo. +const char* K_GetFilenameFromInfo( const K_FindInfo* i_pFindInfo ) +{ + if( !i_pFindInfo ) + { + return 0; + } + +#ifdef WIN32 + return i_pFindInfo->m_stFindData.name; +#elif defined K_LINUX_PLATFORM + return i_pFindInfo->m_pFTSENT->fts_name; +#else +/* + * Directory traversal code is not yet available for Solaris. + * If such code will need to be written, then it will probably use ftw.h. + */ + FATAL_ASSERT( 0 ); + return 0; +#endif +} + +// Forward declarations +int K_FindFileNext( K_FindInfo* io_pFindInfo ); +void K_FindFileClose( K_FindInfo* io_pFindInfo ); + +// Returns 0 if successful, 1 if not found, -1 if error. +// If not error, K_FindFileClose must be called. +// o_pFindInfo must not be null. +int K_FindFileFirst( const char* i_sDirectoryName, K_FindInfo* o_pFindInfo ) +{ +#ifdef WIN32 + char* sSearchString = 0; + int iSearchStringIndex = 0; +#endif + + if ( !i_sDirectoryName || (strlen(i_sDirectoryName) <= 0) || !o_pFindInfo ) + { + return -1; + } + +#ifdef WIN32 + memset( o_pFindInfo, 0, sizeof(K_FindInfo) ); + + iSearchStringIndex = strlen(i_sDirectoryName); + if ( i_sDirectoryName[iSearchStringIndex-1] == PATH_SEPARATOR ) + { + iSearchStringIndex += 2; + } + else + { + iSearchStringIndex += 3; + } + + sSearchString = (char*)calloc( iSearchStringIndex, 1 ); + if ( !sSearchString ) + { + return -1; + } + + strcpy( sSearchString, i_sDirectoryName ); + iSearchStringIndex--; + sSearchString[iSearchStringIndex] = '\0'; + iSearchStringIndex--; + sSearchString[iSearchStringIndex] = '*'; + iSearchStringIndex--; + sSearchString[iSearchStringIndex] = PATH_SEPARATOR; + + o_pFindInfo->m_hFile = _findfirst( sSearchString, &o_pFindInfo->m_stFindData ); + free( sSearchString ); + if ( o_pFindInfo->m_hFile == -1 ) + { + if ( errno == ENOENT ) + { + return 1; + } + else + { + return -1; + } + } +#elif defined K_LINUX_PLATFORM + memset( o_pFindInfo, 0, sizeof(K_FindInfo) ); + + o_pFindInfo->m_pFTS = fts_open( aPath, FTS_PHYSICAL | FTS_NOSTAT, fts_compare ); + if ( !o_pFindInfo->m_pFTS ) + { + return -1; + } + + o_pFindInfo->m_pFTSENT = fts_read( o_pFindInfo->m_pFTS ); + if ( !o_pFindInfo->m_pFTSENT ) + { + if ( errno == 0 ) + { + return 1; + } + else + { + fts_close( o_pFindInfo->m_pFTS ); + return -1; + } + } +#else +/* + * Directory traversal code is not yet available for Solaris. + * If such code will need to be written, then it will probably use ftw.h. + */ +#endif + + // If what we found is not actually a file, get the next hit. +#ifdef WIN32 + if ( (o_pFindInfo->m_stFindData.attrib & _A_SUBDIR) ) +#elif defined K_LINUX_PLATFORM + if ( !(o_pFindInfo->m_pFTSENT->fts_info & FTS_F) ) +#else +/* + * Directory traversal code is not yet available for Solaris. + * If such code will need to be written, then it will probably use ftw.h. + */ +#endif + { + int iNextReturn = K_FindFileNext( o_pFindInfo ); + if ( iNextReturn < 0 ) + { + K_FindFileClose( o_pFindInfo ); + return -1; + } + else + { + return iNextReturn; + } + } + +#if defined(WIN32) || defined(K_LINUX_PLATFORM) + return 0; +#endif +} + +// Returns 0 if successful, 1 if not found, -1 if error. +int K_FindFileNext( K_FindInfo* io_pFindInfo ) +{ + if ( !io_pFindInfo ) + { + return -1; + } + +#ifdef WIN32 + if ( _findnext( io_pFindInfo->m_hFile, &io_pFindInfo->m_stFindData ) != 0 ) + { + return (errno == ENOENT) ? 1 : -1; + } +#elif defined K_LINUX_PLATFORM + io_pFindInfo->m_pFTSENT = fts_read( io_pFindInfo->m_pFTS ); + if ( !io_pFindInfo->m_pFTSENT ) + { + return (errno == 0) ? 1 : -1; + } +#else +/* + * Directory traversal code is not yet available for Solaris. + * If such code will need to be written, then it will probably use ftw.h. + */ +#endif + + // If what we found is not actually a file, get the next hit. +#ifdef WIN32 + if ( (io_pFindInfo->m_stFindData.attrib & _A_SUBDIR) ) +#elif defined K_LINUX_PLATFORM + if ( !(io_pFindInfo->m_pFTSENT->fts_info & FTS_F) ) +#else +/* + * Directory traversal code is not yet available for Solaris. + * If such code will need to be written, then it will probably use ftw.h. + */ +#endif + { + return K_FindFileNext( io_pFindInfo ); + } + +#if defined(WIN32) || defined(K_LINUX_PLATFORM) + return 0; +#endif +} + +void K_FindFileClose( K_FindInfo* io_pFindInfo ) +{ + if ( !io_pFindInfo ) + { + return; + } + +#ifdef WIN32 + _findclose( io_pFindInfo->m_hFile ); +#elif defined K_LINUX_PLATFORM + fts_close( io_pFindInfo->m_pFTS ); +#else +/* + * Directory traversal code is not yet available for Solaris. + * If such code will need to be written, then it will probably use ftw.h. + */ +#endif +} + + +/*--------------------------------------------------------------------------- + * Function: K_GetFilenamesInDirectoryCount + * + * Description: + * Reads the given directory and returns the number of files that it contains. + * + * Input + * ----- + * i_sDirectoryName Name of directory + * + * Output + * ------ + * (none) + * + * Return value Number of files on success, -1 on failure + * + *--------------------------------------------------------------------------*/ + +int K_GetFilenamesInDirectoryCount( const char* i_sDirectoryName ) +{ + K_FindInfo stFindInfo; + int iCurrentFile = 0; + int iError = 0; + + if ( !i_sDirectoryName || (strlen(i_sDirectoryName) <= 0) ) + { + return -1; + } + + iError = K_FindFileFirst( i_sDirectoryName, &stFindInfo ); + if ( iError < 0 ) + { + // error + return -1; + } + else if ( iError > 0 ) + { + // no files found + K_FindFileClose( &stFindInfo ); + return 0; + } + + while ( 1 ) + { + iCurrentFile++; + + iError = K_FindFileNext( &stFindInfo ); + if ( iError < 0 ) + { + // error + K_FindFileClose( &stFindInfo ); + return -1; + } + else if ( iError > 0 ) + { + // no more files found + break; + } + } + + K_FindFileClose( &stFindInfo ); + + return iCurrentFile; +} + + +/*--------------------------------------------------------------------------- + * Function: K_GetFilenamesInDirectory + * + * Description: + * Reads the given directory and returns an array of names of files that it + * contains. A null pointer appears at the last item in the array. The + * caller must deallocate o_pasFilenames by using K_FreeFilenames or by + * calling free() for each file name and then calling free() on the array + * itself. + * + * Input + * ----- + * i_sDirectoryName Name of directory + * + * Output + * ------ + * o_pasFilenames Array of names of files found in this directory + * + * Return value Number of files on success, -1 on failure + * + *--------------------------------------------------------------------------*/ + +int K_GetFilenamesInDirectory( + const char* i_sDirectoryName, + char*** o_pasFilenames ) +{ + // Note that we iterate through the filenames twice -- once to get the count + // (K_GetFilenamesInDirectoryCount) and then once to get all the names. But + // it may happen that the count changes between these calls. So we'll retrieve + // at most the number of files that's returned in the first pass. + + K_FindInfo stFindInfo; + int iFilenameCount = 0, iCurrentFile = 0; + int iError = 0; + + if ( !i_sDirectoryName || (strlen(i_sDirectoryName) <= 0) || !o_pasFilenames ) + { + return -1; + } + + *o_pasFilenames = 0; + + iFilenameCount = K_GetFilenamesInDirectoryCount( i_sDirectoryName ); + + if ( iFilenameCount < 0 ) + { + return -1; + } + + iError = K_FindFileFirst( i_sDirectoryName, &stFindInfo ); + if ( iError < 0 ) + { + // error + return -1; + } + else if ( iError > 0 ) + { + // No files found + K_FindFileClose( &stFindInfo ); + return 0; + } + + *o_pasFilenames = (char**)calloc( (iFilenameCount+1), sizeof(char*) ); // +1 for the null last one + if ( !*o_pasFilenames ) + { + // Out of memory + K_FindFileClose( &stFindInfo ); + return -1; + } + + while ( 1 ) + { + const char* sFilename = K_GetFilenameFromInfo( &stFindInfo ); + + size_t iFilenameLength = sFilename ? strlen( sFilename ) : 0; + + if ( iFilenameLength <= 0 ) + { + K_FreeFilenames( *o_pasFilenames ); + K_FindFileClose( &stFindInfo ); + return -1; + } + + (*o_pasFilenames)[iCurrentFile] = (char*)calloc( (iFilenameLength+1), sizeof(char) ); + if ( !(*o_pasFilenames)[iCurrentFile] ) + { + K_FreeFilenames( *o_pasFilenames ); + K_FindFileClose( &stFindInfo ); + return -1; + } + + strncpy( (*o_pasFilenames)[iCurrentFile], sFilename, iFilenameLength ); + (*o_pasFilenames)[iCurrentFile][iFilenameLength] = '\0'; + + iCurrentFile++; + + if ( iCurrentFile >= iFilenameCount ) + { + break; + } + + iError = K_FindFileNext( &stFindInfo ); + if ( iError < 0 ) + { + // error + K_FindFileClose( &stFindInfo ); + return -1; + } + else if ( iError > 0 ) + { + // no more files found + break; + } + } + + K_FindFileClose( &stFindInfo ); + + return iCurrentFile; +} + + +/*--------------------------------------------------------------------------- + * Function: K_FreeFilenames + * + * Description: + * Deallocates the memory allocated in a successful call to + * K_GetFilenamesInDirectory. + * + * Input + * ----- + * i_asFilenames Array of names of files + * + * Output + * ------ + * (none) + * + * Return value (none) + * + *--------------------------------------------------------------------------*/ + +void K_FreeFilenames( char** i_asFilenames ) +{ + int i; + + if ( !i_asFilenames ) + { + return; + } + + for ( i = 0; (i_asFilenames[i] != 0); i++ ) + { + free( i_asFilenames[i] ); + i_asFilenames[i] = 0; + } + + free( i_asFilenames ); +} + + +/*--------------------------------------------------------------------------- + * Function: K_AdjustLocalClock + * + * Description: + * The K_AdjustLocalClock function gradually adjusts the system clock by + * the given number of seconds. A positive number adjusts the system + * clock forward; a negative number adjusts the system clock backward. + * + * Input + * ----- + * i_iAdjustmentInSeconds Number of seconds by which to adjust the + * system clock + * Output + * ------ + * (none) + * + * Return value 1 if successful, 0 on error + * + *--------------------------------------------------------------------------*/ + +int K_AdjustLocalClock( int i_iNumberOfSeconds ) +{ + struct timeval delta, lastchange; + +#ifndef K_SOLARIS_PLATFORM + /* Only supported/tested on Solaris at the moment */ + + return -1; +#else + /* WARNING: uses standard C time functions with Year 2038 limitations */ + time_t now; + + if ( (now = time(NULL)) == ((time_t)-1) ) + { + return -1; + } + + delta.tv_sec = i_iNumberOfSeconds; + delta.tv_usec = 0; + + return adjtime(&delta, &lastchange); +#endif +} + + +#ifdef K_SOLARIS_PLATFORM +static int pam_tty_conv( + int num_msg, + struct pam_message** mess, + struct pam_response** resp, + void* my_data) +{ + // Following code implements a console-based PAM "conversation" function + // (based sample code from Solaris 10 Software Developer Collection >> + // Solaris Security for Developers Guide >> + // 3. Writing PAM Applications and Services) + + struct pam_message* m = *mess; + struct pam_response* r; + int i, j; + const char* sPassword = (const char*)my_data; + int error = PAM_CONV_ERR; + + if (num_msg <= 0 || num_msg >= PAM_MAX_NUM_MSG) + { + (void) fprintf(stderr, "PAM error: bad number of messages"); + *resp = NULL; + return (PAM_CONV_ERR); + } + + if ((*resp = r = calloc(num_msg, sizeof (struct pam_response))) == NULL) + { + return (PAM_BUF_ERR); + } + + // Loop through messages + for (i = 0; i < num_msg; i++) { + + // bad message from service module + if (m->msg == NULL) + { + (void) fprintf(stderr, "PAM error: bad message"); + goto err; + } + + // fix up final newline: removed for prompts, added back for messages + if (m->msg[strlen(m->msg)] == '\n') + { + m->msg[strlen(m->msg)] = '\0'; + } + + // Since the KMA has its own password prompts and enforces its own rule checks, we already have the + // new password in memory. So instead of displaying PAM prompts and collecting user responses, we + // "automate" by assuming that the prompts correspond to the standard sequence of "New password:" + // followed by "Confirm password:" and so in each case we immediately return the password we already + // have in memory. This violates the PAM "conversation" function instructions (which say, basically, + // not to assume any particular sequence of prompts since there could be any number of underlying + // password managers), but since the KMA is running on an appliance with a fixed password manager, + // our assumptions should hold. + + r->resp = NULL; + r->resp_retcode = 0; + switch (m->msg_style) + { + case PAM_PROMPT_ECHO_OFF: + case PAM_PROMPT_ECHO_ON: + // Assume the prompt asked for New/Confirm password, so return password. + if ( (r->resp = strdup(sPassword)) == NULL ) + { + error = PAM_BUF_ERR; + goto err; + } + break; + + case PAM_ERROR_MSG: + // Assuming the system is configured properly and the KMA password prompts enforce password strength rules, + // there should not be errors because of weak passwords, etc. Still, print errors so users/support can + // diagnose problems. + (void) fputs(m->msg, stderr); + (void) fputc('\n', stderr); + break; + + case PAM_TEXT_INFO: + // Supress prompts (again, making assumptions). + break; + + default: + (void) fprintf(stderr, "PAM error: unknown message"); + goto err; + } + if (errno == EINTR) + { + goto err; + } + + // next message/response + m++; + r++; + } + return (PAM_SUCCESS); + +err: + // Service modules do not clean up responses if an error is returned. + // Free responses here. + for (j = 0; j < i; j++, r++) + { + if (r->resp) + { + // clear before freeing -- may be a password + bzero(r->resp, strlen(r->resp)); + free(r->resp); + r->resp = NULL; + } + } + free(r); + *resp = NULL; + return error; +} +#endif + + +/*--------------------------------------------------------------------------- + * Function: K_SetRootPassword + * + * Description: + * The K_SetRootPassword function sets the password for the root user via + * Pluggable Authentication Module (PAM). This function is interactive. + * + * Input + * ----- + * i_sPassword Password to set + * + * Output + * ------ + * (none) + * + * Return value 0 if successful, -1 on error + * + *--------------------------------------------------------------------------*/ + +int K_SetRootPassword( const char* i_sPassword ) +{ + // Only supported/tested on Solaris at the moment +#ifndef K_SOLARIS_PLATFORM + return -1; +#else + // Based on sample code from Solaris 10 Software Developer Collection >> + // Solaris Security for Developers Guide >> + // 3. Writing PAM Applications and Services + + // TODO: Return PAM error codes (to be logged) instead of emitting + // messages to screen? + + struct pam_conv conv; + pam_handle_t *pamh; + int err; + + conv.conv = pam_tty_conv; + conv.appdata_ptr = (void*)i_sPassword; + + // Initialize PAM framework + err = pam_start("KeyMgr", "root", &conv, &pamh); + if (err != PAM_SUCCESS) + { + fprintf(stderr, "PAM error: %s\n", pam_strerror(pamh, err)); + return -1; + } + + // Change password + err = pam_chauthtok(pamh, 0); + if (err != PAM_SUCCESS) + { + fprintf(stderr, "PAM error: %s\n", pam_strerror(pamh, err)); + // fall through to cleanup + } + + // Cleanup session + pam_end(pamh, 0); + + return (err == PAM_SUCCESS) ? 0 : -1; +#endif +} + + +/*--------------------------------------------------------------------------- + * Function: K_Alarm + * + * Description: + * Calls alarm(2) on Unix in order to cause the operating system to generate + * a SIGALRM signal for this process after the given number of real-time + * seconds. Does nothing on Windows. + * + * Input + * ----- + * i_iSeconds Number of seconds after which to generate a SIGALRM + * signal + * + * Output + * ------ + * (none) + * + * Return value If a previous alarm request is pending, then it returns + * the number of seconds until this previous request would + * have generated a SIGALRM signal. Otherwise, returns 0. + * + *--------------------------------------------------------------------------*/ + +unsigned int K_Alarm( unsigned int i_iSeconds ) +{ +#ifndef WIN32 + return alarm( i_iSeconds ); +#else + return 0; +#endif +} + + +/*--------------------------------------------------------------------------- + * Function: K_GetExtendedVersionFromBase + * + * Description: + * This KMS-specific function prepends the timestamp value to the specified + * base replication schema version and returns this value as an extended + * replication schema version. + * + * Input + * ----- + * i_iBaseSchemaVersion Base replication schema version + * + * Output + * ------ + * (none) + * + * Return value Extended replication schema version + * + *--------------------------------------------------------------------------*/ + +unsigned int K_GetExtendedVersionFromBase( unsigned int i_iBaseSchemaVersion ) +{ + // seconds since 1970, force to 32-bit +#ifdef WIN32 + INT32 iTimeStamp = (INT32) time(NULL); +#else + int32_t iTimeStamp = (int32_t) time(NULL); +#endif + // minutes since 1970 + iTimeStamp = iTimeStamp / 60; + // minutes since 2000 (approximately) + iTimeStamp -= (30*365*24*60); + // shift 8 bits to clear out room for schema version # + iTimeStamp = iTimeStamp << 8; + // add schema version # to lower end + iTimeStamp |= i_iBaseSchemaVersion; + + return (unsigned int) iTimeStamp; + +} + + +/*--------------------------------------------------------------------------- + * Function: K_ParseTimestampFromExtendedVersion + * + * Description: + * This KMS-specific function parses the timestamp value from the given + * extended replication schema version and returns this timestamp value. + * + * Input + * ----- + * i_iExtendedSchemaVersion Extended replication schema version + * + * Output + * ------ + * (none) + * + * Return value Timestamp value + * + *--------------------------------------------------------------------------*/ + +unsigned int K_ParseTimestampFromExtendedVersion( + unsigned int i_iExtendedSchemaVersion ) +{ + unsigned int iTimeStamp = i_iExtendedSchemaVersion >> 8; + + return iTimeStamp; +} + + +/*--------------------------------------------------------------------------- + * Function: K_ParseBaseFromExtendedVersion + * + * Description: + * This KMS-specific function parses the base replication schema value from + * the given extended replication schema version and returns this base value. + * + * Input + * ----- + * i_iExtendedSchemaVersion Extended replication schema version + * + * Output + * ------ + * (none) + * + * Return value Base replication schema value + * + *--------------------------------------------------------------------------*/ + +unsigned int K_ParseBaseFromExtendedVersion( + unsigned int i_iExtendedSchemaVersion ) +{ + unsigned int iBaseSchemaVersion = i_iExtendedSchemaVersion & 0x000000FF; + + return iBaseSchemaVersion; +} + + +/*--------------------------------------------------------------------------- + * Function: K_System + * + * Description: + * This function is a thread-safe replacement for the unsafe system(3C) call. + * See the popen(3C) man page for more information. + * + * Input + * ----- + * i_sCmd Command to execute + * + * Output + * ------ + * (none) + * + * Return value Termination status of the command language interpreter + * if successful, -1 on failure + * + *--------------------------------------------------------------------------*/ + +int K_System( const char *i_sCmd ) +{ +#ifndef WIN32 + FILE *p; + int rc; + struct sigaction sOldAction; + + // Save signal handler + sigaction( SIGCHLD, NULL, &sOldAction ); + + // Use default child signal handler + sigset( SIGCHLD, SIG_DFL ); + + p = popen( i_sCmd, "w" ); + if ( p == NULL ) + { + rc = -1; + } + else + { + rc = pclose( p ); + } + + // Reset signal handler + sigset( SIGCHLD, sOldAction.sa_handler ); + + return rc; +#else + return system( i_sCmd ); +#endif +} +