CClientEndPoint.cpp [plain text]
#include <stdio.h>
#include <stdlib.h> // for malloc()
#include <string.h>
#include <unistd.h> // for getpid()
#include <time.h> // for time()
#include <mach/mach.h>
#include <mach/mach_error.h>
#include <servers/bootstrap.h>
#include <syslog.h>
#include <bsm/libbsm.h>
#include "CClientEndPoint.h"
#include "DirServicesTypes.h"
#include "DirServicesConst.h"
#include "DirServicesPriv.h"
#include "PrivateTypes.h"
#include "DSCThread.h"
#include "DirectoryServiceMIG.h"
#define kMsgSize sizeof( sComData )
#define kIPCMsgSize sizeof( sIPCMsg )
CClientEndPoint::CClientEndPoint ( const char *inSrvrName )
{
if ( inSrvrName != nil )
fServiceName = strdup( inSrvrName );
else
fServiceName = strdup( kDSStdMachPortName );
fReplyMsg = NULL;
fServicePort = MACH_PORT_NULL;
fSessionPort = MACH_PORT_NULL;
}
CClientEndPoint::~CClientEndPoint ( void )
{
DSFree( fServiceName );
DSFree( fReplyMsg );
Disconnect();
if ( fServicePort != MACH_PORT_NULL )
{
mach_port_deallocate( mach_task_self(), fServicePort );
fServicePort = MACH_PORT_NULL;
}
}
SInt32 CClientEndPoint::Connect( void )
{
SInt32 siResult = eDSNoErr;
kern_return_t kr = KERN_FAILURE;
tryAgain:
if ( fServicePort == MACH_PORT_NULL )
{
kr = bootstrap_look_up( bootstrap_port, fServiceName, &fServicePort );
if ( kr != KERN_SUCCESS ) {
siResult = eServerNotRunning;
LOG3( kStdErr, "*** failed bootstrap_look_up: %s at: %d: Msg = %s\n", __FILE__, __LINE__, mach_error_string( kr ) );
}
}
if ( siResult == eDSNoErr && fSessionPort == MACH_PORT_NULL )
{
audit_token_t atoken;
uid_t euid = -1;
kr = dsmig_create_api_session( fServicePort, &fSessionPort, &atoken );
switch ( kr )
{
case MACH_SEND_INVALID_DEST:
mach_port_deallocate( mach_task_self(), fServicePort );
fServicePort = MACH_PORT_NULL;
goto tryAgain;
case KERN_SUCCESS:
audit_token_to_au32( atoken, NULL, &euid, NULL, NULL, NULL, NULL, NULL, NULL );
if ( euid != 0 ) {
dsmig_close_api_session( fSessionPort );
mach_port_deallocate( mach_task_self(), fSessionPort );
fSessionPort = MACH_PORT_NULL;
siResult = eServerSendError;
syslog( LOG_ALERT, "Attempt to connect to a daemon that is not running as root (euid != 0)" );
}
break;
default:
siResult = eServerSendError;
break;
}
}
return siResult;
}
void CClientEndPoint::Disconnect( void )
{
if ( fSessionPort != MACH_PORT_NULL )
{
dsmig_close_api_session( fSessionPort );
mach_port_deallocate( mach_task_self(), fSessionPort );
fSessionPort = MACH_PORT_NULL;
}
}
SInt32 CClientEndPoint::SendMessage( sComData *inMsg )
{
SInt32 result = eServerSendError;
bool bTryAgain = false;
do
{
kern_return_t kr = MACH_SEND_INVALID_DEST;
mach_msg_type_name_t serverPoly = MACH_MSG_TYPE_COPY_SEND;
if( fSessionPort != MACH_PORT_NULL )
{
char replyFixedBuffer[ kMaxFixedMsg ];
sComDataPtr replyFixedData = (sComDataPtr) replyFixedBuffer;
mach_msg_type_number_t replyFixedLen = 0;
vm_address_t sendData = 0;
mach_msg_type_number_t sendLen = sizeof(sComData) + inMsg->fDataLength - 1;
vm_address_t replyData = 0;
mach_msg_type_number_t replyLen = 0;
if( inMsg->fDataLength <= kMaxFixedMsgData )
{
kr = dsmig_api_call( fSessionPort, serverPoly, inMsg, sendLen, 0, 0, replyFixedData, &replyFixedLen, &replyData, &replyLen );
}
else
{
vm_read( mach_task_self(), (vm_address_t)inMsg, sendLen, &sendData, &sendLen );
kr = dsmig_api_call( fSessionPort, serverPoly, NULL, 0, sendData, sendLen, replyFixedData, &replyFixedLen, &replyData, &replyLen );
if( kr == MACH_SEND_INVALID_DEST )
{
vm_deallocate( mach_task_self(), sendData, sendLen );
}
}
if( kr == KERN_SUCCESS )
{
sComDataPtr pComData = NULL;
UInt32 uiLength = 0;
if( replyFixedLen )
{
pComData = (sComDataPtr) replyFixedData;
uiLength = replyFixedLen;
}
else if( replyLen )
{
pComData = (sComDataPtr) replyData;
uiLength = replyLen;
}
if( pComData != NULL && pComData->fDataLength == (uiLength - (sizeof(sComData) - 1)) )
{
fReplyMsg = (sComData *) calloc( sizeof(char), sizeof(sComData) + pComData->fDataSize );
bcopy( pComData, fReplyMsg, uiLength );
result = eDSNoErr;
}
if( replyLen )
{
vm_deallocate( mach_task_self(), replyData, replyLen );
}
}
}
if( bTryAgain == false && kr == MACH_SEND_INVALID_DEST )
{
Disconnect();
if ( Connect() == eDSNoErr )
bTryAgain = true;
}
else
{
bTryAgain = false;
}
} while( bTryAgain );
return result;
}
SInt32 CClientEndPoint::GetReplyMessage( sComData **outMsg )
{
SInt32 siResult = eServerReplyError;
if ( fReplyMsg != NULL )
{
DSFree( *outMsg );
*outMsg = fReplyMsg;
fReplyMsg = NULL;
siResult = eDSNoErr;
}
return siResult;
}