#if DEBUG_SRVR
# include <stdio.h> // for stderr, fprintf(), et al
#endif
#include "ServerControl.h"
#include "DirServicesConst.h"
#include "DirServicesPriv.h"
#include "CHandlers.h"
#include "DSTCPListener.h"
#include "CMsgQueue.h"
#include "CRefTable.h"
#include "DSMutexSemaphore.h"
#include "DSCThread.h"
#include "CServerPlugin.h"
#include "CPluginHandler.h"
#include "CNodeList.h"
#include "CLog.h"
#include "CPluginConfig.h"
#include "SharedConsts.h"
#include "CFile.h"
#include "CAuditUtils.h"
#include "DSMachEndian.h"
#include <mach/mach.h>
#include <mach/mach_error.h>
#include <mach/notify.h>
#include <sys/stat.h> //used for mkdir and stat
#include <servers/bootstrap.h>
#include <IOKit/pwr_mgt/IOPMLib.h> //required for power management handling
#include <syslog.h> // for syslog()
#include <time.h> // for time
#include <bsm/libbsm.h>
extern "C" {
#include "DirectoryServiceMIGServer.h"
}
extern "C" int mbr_reset_cache(); extern "C" int _lookupd_port(int); extern "C" int _lookup_link(mach_port_t, char *, int *);
extern "C" int _lookup_one(mach_port_t, int, char *, int, char **, int *);
extern "C" int _lu_running();
extern void LoggingTimerCallBack( CFRunLoopTimerRef timer, void *info );
extern void dsPMNotificationHandler ( void *refContext, io_service_t service, natural_t messageType, void *notificationID );
extern io_object_t gPMDeregisterNotifier;
extern io_connect_t gPMKernelPort;
extern void NetworkChangeCallBack(SCDynamicStoreRef aSCDStore, CFArrayRef changedKeys, void *callback_argument);
extern CFRunLoopRef gServerRunLoop;
extern CFAbsoluteTime gSunsetTime;
extern dsBool gLogAPICalls;
extern dsBool gDebugLogging;
extern dsBool gDSFWCSBPDebugLogging;
extern bool gServerOS;
extern mach_port_t gServerMachPort;
CFRunLoopTimerRef ServerControl::fNSPCTimerRef = NULL;
CFRunLoopTimerRef ServerControl::fLDFCTimerRef = NULL;
CFRunLoopTimerRef ServerControl::fMDFCTimerRef = NULL;
CFRunLoopTimerRef ServerControl::fNIASTimerRef = NULL;
uInt32 gAPICallCount = 0;
ServerControl *gSrvrCntl = nil;
CRefTable *gRefTable = nil;
CPlugInList *gPlugins = nil;
CMsgQueue *gTCPMsgQueue = nil;
CPluginConfig *gPluginConfig = nil;
CNodeList *gNodeList = nil;
CPluginHandler *gPluginHandler = nil;
DSMutexSemaphore *gTCPHandlerLock = new DSMutexSemaphore(); DSMutexSemaphore *gPerformanceLoggingLock = new DSMutexSemaphore(); DSMutexSemaphore *gLazyPluginLoadingLock = new DSMutexSemaphore(); DSMutexSemaphore *gHashAuthFailedMapLock = new DSMutexSemaphore(); DSMutexSemaphore *gMachThreadLock = new DSMutexSemaphore(); DSMutexSemaphore *gTimerMutex = new DSMutexSemaphore();
uInt32 gDaemonPID;
uInt32 gDaemonIPAddress;
uInt32 gRefCountWarningLimit = 500;
uInt32 gDelayFailedLocalAuthReturnsDeltaInSeconds = 1;
uInt32 gMaxHandlerThreadCount = kMaxHandlerThreads;
dsBool gToggleDebugging = false;
mach_port_t gMachAPISet = 0;
map<mach_port_t, pid_t> gPIDMachMap;
char *gNIHierarchyTagString = nil;
uInt32 gActiveMachThreads = 0;
uInt32 gActiveLongRequests = 0;
bool gFirstNetworkUpAtBoot = false;
static void DoSearchPolicyChange(CFRunLoopTimerRef timer, void *info);
void DoSearchPolicyChange(CFRunLoopTimerRef timer, void *info)
{
if ( info != nil )
{
((ServerControl *)info)->DoNodeSearchPolicyChange();
}
}
static void DoLookupDaemonFlushCache(CFRunLoopTimerRef timer, void *info);
void DoLookupDaemonFlushCache(CFRunLoopTimerRef timer, void *info)
{
if ( info != nil )
{
((ServerControl *)info)->FlushLookupDaemonCache();
}
}
static void DoMemberDaemonFlushCache(CFRunLoopTimerRef timer, void *info);
void DoMemberDaemonFlushCache(CFRunLoopTimerRef timer, void *info)
{
if ( info != nil )
{
((ServerControl *)info)->FlushMemberDaemonCache();
}
}
static void DoNIAutoSwitchNetworkChange(CFRunLoopTimerRef timer, void *info);
void DoNIAutoSwitchNetworkChange(CFRunLoopTimerRef timer, void *info)
{
if ( info != nil )
{
((ServerControl *)info)->NIAutoSwitchCheck();
}
}
CFStringRef SearchPolicyChangeCopyStringCallback( const void *item );
CFStringRef SearchPolicyChangeCopyStringCallback( const void *item )
{
return CFSTR("SearchPolicyChange");
}
CFStringRef LookupDaemonFlushCacheCopyStringCallback( const void *item );
CFStringRef LookupDaemonFlushCacheCopyStringCallback( const void *item )
{
return CFSTR("LookupDaemonFlushCache");
}
CFStringRef MemberDaemonFlushCacheCopyStringCallback( const void *item );
CFStringRef MemberDaemonFlushCacheCopyStringCallback( const void *item )
{
return CFSTR("MemberDaemonFlushCache");
}
CFStringRef NetworkChangeNIAutoSwitchCopyStringCallback( const void *item );
CFStringRef NetworkChangeNIAutoSwitchCopyStringCallback( const void *item )
{
return CFSTR("NetworkChangeNIAutoSwitchCheck");
}
void DoPeriodicTask(CFRunLoopTimerRef timer, void *info);
CFStringRef PeriodicTaskCopyStringCallback( const void *item );
CFStringRef PeriodicTaskCopyStringCallback( const void *item )
{
return CFSTR("PeriodicTask");
}
#pragma mark -
#pragma mark MIG Support Routines
void mig_spawnonceifnecessary( void )
{
gMachThreadLock->Wait();
bool bSpawnThread = ( gActiveMachThreads < gMaxHandlerThreadCount && gActiveLongRequests > gActiveMachThreads );
gMachThreadLock->Signal();
if( bSpawnThread )
{
CMigHandlerThread* aMigHandlerThread = new CMigHandlerThread(DSCThread::kTSMigHandlerThread, true);
if (aMigHandlerThread != NULL)
aMigHandlerThread->StartThread();
}
}
#pragma mark -
#pragma mark MIG Call Handler Routines
kern_return_t dsmig_do_checkUsernameAndPassword( mach_port_t server,
sStringPtr username,
sStringPtr password,
int32_t *result,
audit_token_t atoken )
{
CRequestHandler handler;
char *debugDataTag = NULL;
gMachThreadLock->Wait();
gActiveLongRequests++;
gMachThreadLock->Signal();
mig_spawnonceifnecessary();
if ( (gDebugLogging) || (gLogAPICalls) )
{
pid_t aPID;
audit_token_to_au32( atoken, NULL, NULL, NULL, NULL, NULL, &aPID, NULL, NULL );
debugDataTag = handler.BuildAPICallDebugDataTag( gDaemonIPAddress, aPID, "checkpw()", "Server" );
DBGLOG2( kLogHandler, "%s : dsmig DAC : Username = %s", debugDataTag, username );
}
#if USE_BSM_AUDIT
uid_t auidp;
uid_t euidp;
gid_t egidp;
uid_t ruidp;
gid_t rgidp;
pid_t pidp;
au_asid_t asidp;
au_tid_t tidp;
audit_token_to_au32( atoken, &auidp, &euidp, &egidp, &ruidp, &rgidp, &pidp, &asidp, &tidp );
char *textStr = nil;
uInt32 bsmEventCode = AuditForThisEvent( kCheckUserNameAndPassword, username, &textStr );
#endif
*result = handler.DoCheckUserNameAndPassword( username, password, eDSExact, NULL, NULL );
#if USE_BSM_AUDIT
if ( bsmEventCode > 0 )
{
token_t *tok;
if ( *result == eDSNoErr )
{
tok = au_to_text( textStr );
audit_write_success( bsmEventCode, tok,
auidp,
euidp,
egidp,
ruidp,
rgidp,
pidp,
asidp,
&tidp );
}
else
{
audit_write_failure( bsmEventCode, textStr, (int)*result,
auidp,
euidp,
egidp,
ruidp,
rgidp,
pidp,
asidp,
&tidp );
}
}
DSFreeString( textStr ); #endif
if ( debugDataTag )
{
DBGLOG3( kLogHandler, "%s : dsmig DAR : Username %s : Result code = %d", debugDataTag, username, *result );
free( debugDataTag );
}
gMachThreadLock->Wait();
gActiveLongRequests--;
gMachThreadLock->Signal();
return KERN_SUCCESS;
}
kern_return_t dsmig_do_create_api_session( mach_port_t server, mach_port_t *newServer, audit_token_t atoken )
{
mach_port_t oldTargetOfNotification = MACH_PORT_NULL;
(void) mach_port_allocate( mach_task_self(), MACH_PORT_RIGHT_RECEIVE, newServer );
(void) mach_port_move_member( mach_task_self(), *newServer, gMachAPISet );
(void) mach_port_request_notification( mach_task_self(), *newServer, MACH_NOTIFY_NO_SENDERS, 1, *newServer, MACH_MSG_TYPE_MAKE_SEND_ONCE, &oldTargetOfNotification );
pid_t aPID;
audit_token_to_au32( atoken, NULL, NULL, NULL, NULL, NULL, &aPID, NULL, NULL );
gMachThreadLock->Wait();
gPIDMachMap[*newServer] = aPID;
gMachThreadLock->Signal();
return KERN_SUCCESS;
}
kern_return_t dsmig_do_api_call( mach_port_t server,
mach_msg_type_name_t serverPoly,
sComDataPtr msg_data,
mach_msg_type_number_t msg_dataCnt,
vm_offset_t msg_data_ool,
mach_msg_type_number_t msg_data_oolCnt,
sComDataPtr reply_msg,
mach_msg_type_number_t *reply_msgCnt,
vm_offset_t *reply_msg_ool,
mach_msg_type_number_t *reply_msg_oolCnt,
audit_token_t atoken )
{
kern_return_t kr = KERN_FAILURE;
sComDataPtr pComData = NULL;
uInt32 uiLength = 0;
uInt32 dataLength = 0;
uInt32 dataSize = 0;
if( msg_dataCnt )
{
pComData = (sComDataPtr) msg_data;
uiLength = msg_dataCnt;
dataLength = pComData->fDataLength;
dataSize = pComData->fDataSize;
#ifdef __LITTLE_ENDIAN__
if (pComData->type.msgt_translate == 1) {
dataLength = DSGetLong(&pComData->fDataLength, false);
dataSize = DSGetLong(&pComData->fDataSize, false);
}
#endif
}
else
{
pComData = (sComDataPtr) msg_data_ool;
uiLength = msg_data_oolCnt;
dataLength = pComData->fDataLength;
dataSize = pComData->fDataSize;
#ifdef __LITTLE_ENDIAN__
if (pComData->type.msgt_translate == 1) {
dataLength = DSGetLong(&pComData->fDataLength, false);
dataSize = DSGetLong(&pComData->fDataSize, false);
}
#endif
}
if( uiLength >= (sizeof(sComData) - 1) )
{
if( dataLength == (uiLength - (sizeof(sComData) - 1)) )
{
sComData *pRequest = (sComData *) calloc( sizeof(sComData) + dataSize, 1 );
CRequestHandler handler;
bcopy( (void *)pComData, pRequest, uiLength );
gMachThreadLock->Wait();
gActiveLongRequests ++;
gMachThreadLock->Signal();
mig_spawnonceifnecessary();
#ifdef __LITTLE_ENDIAN__
if (pRequest->type.msgt_translate == 1) {
DSMachEndian swapper(pRequest, kDSSwapToHost);
swapper.SwapMessage();
}
#endif
audit_token_to_au32( atoken, NULL, (uid_t *)&pRequest->fEffectiveUID, NULL, (uid_t *)&pRequest->fUID, NULL, (pid_t *)&pRequest->fPID, NULL, NULL );
handler.HandleRequest( &pRequest );
gMachThreadLock->Wait();
gActiveLongRequests --;
gMachThreadLock->Signal();
pRequest->fPID = gDaemonPID;
uInt32 dataLen = pRequest->fDataLength;
#ifdef __LITTLE_ENDIAN__
if (pRequest->type.msgt_translate == 1) {
DSMachEndian swapper(pRequest, kDSSwapToBig);
swapper.SwapMessage();
}
#endif
if( sizeof(sComData) + dataLen <= *reply_msgCnt )
{
*reply_msgCnt = sizeof(sComData) + dataLen - 1;
bcopy( pRequest, reply_msg, *reply_msgCnt );
*reply_msg_oolCnt = 0;
}
else
{
*reply_msgCnt = 0; vm_read( mach_task_self(), (vm_address_t)pRequest, (sizeof(sComData) + dataLen - 1), reply_msg_ool, reply_msg_oolCnt );
}
free( pRequest );
pRequest = NULL;
gAPICallCount++;
if ( (gAPICallCount % 1023) == 1023 ) {
if (gLogAPICalls)
{
syslog(LOG_CRIT,"API clients have called APIs %d times", gAPICallCount);
}
}
kr = KERN_SUCCESS;
}
else
{
syslog( LOG_ALERT, "dsmig_do_api_call: Bad message size %d, does not correlate with contents length %d + header %d", uiLength, dataLength, (sizeof(sComData) - 1) );
}
}
else
{
syslog( LOG_ALERT, "dsmig_do_api_call message is too small to be valid message %d < %d", uiLength, sizeof(sComData) - 1 );
}
if( msg_data_oolCnt )
{
vm_deallocate( mach_task_self(), msg_data_ool, msg_data_oolCnt );
}
return kr;
}
#pragma mark -
#pragma mark ServerControl Routines
ServerControl::ServerControl ( void )
{
gDaemonPID = getpid();
gDaemonIPAddress = 0;
fTCPListener = nil;
fTCPHandlerThreadsCnt = 0;
fSCDStore = 0;
fPerformanceStatGatheringActive = false; fLookupDaemonFlushCacheRequestCount = 0;
fMemberDaemonFlushCacheRequestCount = 0;
fHoldStore = NULL;
fTCPHandlers = nil;
#ifdef BUILD_IN_PERFORMANCE
fLastPluginCalled = 0;
fPerfTableNumPlugins = 0;
fPerfTable = nil;
#if PERFORMANCE_STATS_ALWAYS_ON
fPerformanceStatGatheringActive = true;
#else
fPerformanceStatGatheringActive = false;
#endif
#endif
fTCPHandlerSemaphore = new DSSemaphore( fTCPHandlerThreadsCnt );
fServiceNameString = CFStringCreateWithCString( NULL, kDSStdMachPortName, kCFStringEncodingUTF8 );
if (gDaemonPID > 100) {
gFirstNetworkUpAtBoot = true;
}
}
ServerControl::~ServerControl ( void )
{
if ( fTCPHandlerSemaphore != nil )
{
delete( fTCPHandlerSemaphore );
fTCPHandlerSemaphore = nil;
}
}
sInt32 ServerControl::StartUpServer ( void )
{
sInt32 result = eDSNoErr;
struct stat statResult;
try
{
if ( gNodeList == nil )
{
gNodeList = new CNodeList();
if ( gNodeList == nil ) throw((sInt32)eMemoryAllocError);
}
if ( gRefTable == nil )
{
gRefTable = new CRefTable( CHandlerThread::RefDeallocProc );
if ( gRefTable == nil ) throw( (sInt32)eMemoryAllocError );
}
if ( gPluginConfig == nil )
{
gPluginConfig = new CPluginConfig();
if ( gPluginConfig == nil ) throw( (sInt32)eMemoryAllocError );
gPluginConfig->Initialize();
}
fTCPHandlers = (CHandlerThread **)calloc(gMaxHandlerThreadCount, sizeof(CHandlerThread *));
if ( gPlugins == nil )
{
gPlugins = new CPlugInList();
if ( gPlugins == nil ) throw( (sInt32)eMemoryAllocError );
}
if ( gTCPMsgQueue == nil )
{
gTCPMsgQueue = new CMsgQueue();
if ( gTCPMsgQueue == nil ) throw((sInt32)eMemoryAllocError);
}
if (::stat( "/Library/Preferences/DirectoryService/.DSLogAPIAtStart", &statResult ) == eDSNoErr)
{
gSunsetTime = CFAbsoluteTimeGetCurrent() + 300;
CFRunLoopTimerRef timer = CFRunLoopTimerCreate( kCFAllocatorDefault,
gSunsetTime + 1,
0,
0,
0,
LoggingTimerCallBack,
NULL );
CFRunLoopAddTimer( gServerRunLoop, timer, kCFRunLoopDefaultMode );
CFRelease( timer );
timer = NULL;
gLogAPICalls = true;
syslog(LOG_ALERT,"Logging of API Calls turned ON at Startup of DS Daemon.");
gDebugLogging = true;
CLog::StartDebugLog();
syslog(LOG_ALERT,"Debug Logging turned ON at Startup of DS Daemon.");
}
fMigListener = new CMigHandlerThread();
if ( fMigListener == nil ) throw((sInt32)eMemoryAllocError);
fMigListener->StartThread();
if ( ( (::stat( "/Library/Preferences/DirectoryService/.DSTCPListening", &statResult ) == eDSNoErr) ||
(gServerOS) ) &&
(::stat( "/Library/Preferences/DirectoryService/.DSTCPNotListening", &statResult ) != eDSNoErr) )
{
result = StartTCPListener(kDSDefaultListenPort);
if ( result != eDSNoErr ) throw( result );
}
if ( gPluginHandler == nil )
{
gPluginHandler = new CPluginHandler();
if ( gPluginHandler == nil ) throw((sInt32)eMemoryAllocError);
gPluginHandler->StartThread();
}
result = RegisterForSystemPower();
if ( result != eDSNoErr ) throw( result );
result = (sInt32)RegisterForNetworkChange();
if ( result != eDSNoErr ) throw( result );
result = SetUpPeriodicTask();
if ( result != eDSNoErr ) throw( result );
HandleMultipleNetworkTransitionsForNIAutoSwitch();
}
catch( sInt32 err )
{
result = err;
}
return( result );
}
sInt32 ServerControl::ShutDownServer ( void )
{
sInt32 result = eDSNoErr;
uInt32 i = 0;
uInt32 uiStopCnt = 0;
struct stat statResult;
try
{
result = (sInt32)UnRegisterForNetworkChange();
if ( result != eDSNoErr ) throw( result );
mach_port_destroy( mach_task_self(), gMachAPISet );
gMachAPISet = MACH_PORT_NULL;
if (::stat( "/Library/Preferences/DirectoryService/.DSTCPListening", &statResult ) == eDSNoErr)
{
if (fTCPListener != nil)
{
fTCPListener->StopThread();
gTCPHandlerLock->Wait();
for ( i = 0; i < gMaxHandlerThreadCount; i++ )
{
if ( fTCPHandlers[ i ] != nil )
{
uiStopCnt += 1;
fTCPHandlers[ i ]->StopThread();
fTCPHandlers[ i ] = nil;
}
}
gTCPHandlerLock->Signal();
while (uiStopCnt > 0)
{
WakeAHandler(DSCThread::kTSTCPHandlerThread);
uiStopCnt--;
}
uiStopCnt = 0;
}
}
CLog::Deinitialize();
}
catch( sInt32 err )
{
result = err;
}
return( result );
}
sInt32 ServerControl::StartTCPListener ( uInt32 inPort )
{
sInt32 result = eDSNoErr;
try
{
fTCPListener = new DSTCPListener(inPort);
if ( fTCPListener == nil ) throw((sInt32)eMemoryAllocError);
fTCPListener->StartThread();
}
catch( sInt32 err )
{
result = err;
DBGLOG2( kLogApplication, "File: %s. Line: %d", __FILE__, __LINE__ );
DBGLOG1( kLogApplication, " Caught exception = %d.", err );
}
return( result );
}
sInt32 ServerControl::StopTCPListener ( void )
{
sInt32 result = eDSNoErr;
try
{
if ( fTCPListener == nil ) throw((sInt32)eMemoryAllocError);
fTCPListener->StopThread();
}
catch( sInt32 err )
{
result = err;
DBGLOG2( kLogApplication, "File: %s. Line: %d", __FILE__, __LINE__ );
DBGLOG1( kLogApplication, " Caught exception = %d.", err );
}
return( result );
}
sInt32 ServerControl:: StartAHandler ( const FourCharCode inThreadSignature )
{
volatile uInt32 iThread;
sInt32 result = eDSNoErr;
try
{
if (inThreadSignature == DSCThread::kTSTCPHandlerThread)
{
if ( (fTCPHandlerThreadsCnt >= 0) && (fTCPHandlerThreadsCnt < gMaxHandlerThreadCount) )
{
for (iThread =0; iThread < gMaxHandlerThreadCount; iThread++)
{
if (fTCPHandlers[ iThread ] == nil)
{
fTCPHandlers[ iThread ] = new CHandlerThread(DSCThread::kTSTCPHandlerThread, iThread);
if ( fTCPHandlers[ iThread ] == nil ) throw((sInt32)eMemoryAllocError);
fTCPHandlerThreadsCnt++;
fTCPHandlers[ iThread ]->StartThread();
break;
}
else if ( fTCPHandlers[iThread]->GetOurThreadRunState() == DSCThread::kThreadStop)
{
fTCPHandlers[ iThread ] = new CHandlerThread(DSCThread::kTSTCPHandlerThread, iThread);
if ( fTCPHandlers[ iThread ] == nil ) throw((sInt32)eMemoryAllocError);
fTCPHandlers[ iThread ]->StartThread();
break;
}
}
}
}
}
catch( sInt32 err )
{
result = err;
}
return( result );
}
void ServerControl:: WakeAHandler ( const FourCharCode inThreadSignature )
{
if (inThreadSignature == DSCThread::kTSTCPHandlerThread)
{
fTCPHandlerSemaphore->Signal();
}
}
sInt32 ServerControl:: StopAHandler ( const FourCharCode inThreadSignature, uInt32 iThread, CHandlerThread *inThread )
{
sInt32 result = eDSNoErr;
try
{
if (inThreadSignature == DSCThread::kTSTCPHandlerThread)
{
if ( (iThread >= 0) && (iThread < gMaxHandlerThreadCount) )
{
if (fTCPHandlers[ iThread ] == inThread)
{
fTCPHandlers[ iThread ] = nil;
fTCPHandlerThreadsCnt--;
}
}
}
}
catch( sInt32 err )
{
result = err;
}
return( result );
}
void ServerControl:: SleepAHandler ( const FourCharCode inThreadSignature, uInt32 waitTime )
{
if (inThreadSignature == DSCThread::kTSTCPHandlerThread)
{
fTCPHandlerSemaphore->Wait( waitTime );
}
}
uInt32 ServerControl::GetHandlerCount ( const FourCharCode inThreadSignature )
{
if (inThreadSignature == DSCThread::kTSTCPHandlerThread)
{
return fTCPHandlerThreadsCnt;
}
return 0;
}
sInt32 ServerControl:: RegisterForNetworkChange ( void )
{
sInt32 scdStatus = eDSNoErr;
CFStringRef ipKey = 0; CFStringRef dhcpKey = 0; CFStringRef niKey = 0; CFMutableArrayRef notifyKeys = 0;
CFMutableArrayRef notifyPatterns = 0;
Boolean setStatus = FALSE;
CFStringRef aPIDString = NULL;
SCDynamicStoreRef store = NULL;
CFRunLoopSourceRef rls = NULL;
DBGLOG( kLogApplication, "RegisterForNetworkChange(): " );
notifyKeys = CFArrayCreateMutable( kCFAllocatorDefault,
0,
&kCFTypeArrayCallBacks);
notifyPatterns = CFArrayCreateMutable( kCFAllocatorDefault,
0,
&kCFTypeArrayCallBacks);
ipKey = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
CFArrayAppendValue(notifyKeys, ipKey);
CFRelease(ipKey);
ipKey = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
CFArrayAppendValue(notifyPatterns, ipKey);
CFRelease(ipKey);
dhcpKey = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetDHCP);
CFArrayAppendValue(notifyPatterns, dhcpKey);
CFRelease(dhcpKey);
niKey = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetNetInfo);
CFArrayAppendValue(notifyKeys, niKey);
CFRelease(niKey);
store = SCDynamicStoreCreate(NULL, fServiceNameString, NetworkChangeCallBack, NULL);
if (store != NULL && notifyKeys != NULL && notifyPatterns != NULL)
{
SCDynamicStoreSetNotificationKeys(store, notifyKeys, notifyPatterns);
rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
if (rls != NULL)
{
CFRunLoopAddSource(gServerRunLoop, rls, kCFRunLoopDefaultMode);
CFRelease(rls);
rls = NULL;
}
else
{
syslog(LOG_ALERT,"Unable to add source to RunLoop for SystemConfiguration registration for Network Notification");
}
CFRelease(notifyKeys);
notifyKeys = NULL;
CFRelease(notifyPatterns);
notifyPatterns = NULL;
CFRelease(store);
store = NULL;
}
else
{
syslog(LOG_ALERT,"Unable to create DirectoryService store for SystemConfiguration registration for Network Notification");
}
if (fHoldStore == NULL)
{
fHoldStore = SCDynamicStoreCreate(NULL, fServiceNameString, NULL, NULL);
}
if (fHoldStore != NULL)
{
aPIDString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%d"), (uInt32)getpid());
if (aPIDString != NULL)
{
setStatus = SCDynamicStoreAddTemporaryValue( fHoldStore, CFSTR("DirectoryService:PID"), aPIDString );
CFRelease(aPIDString);
}
else
{
syslog(LOG_ALERT,"Unable to create DirectoryService:PID string for SystemConfiguration registration - DSAgent will be disabled in lookupd");
}
}
else
{
syslog(LOG_ALERT,"Unable to create DirectoryService store for SystemConfiguration registration of DirectoryService:PID string - DSAgent will be disabled in lookupd");
}
return scdStatus;
}
sInt32 ServerControl:: UnRegisterForNetworkChange ( void )
{
sInt32 scdStatus = eDSNoErr;
DBGLOG( kLogApplication, "UnRegisterForNetworkChange(): " );
return scdStatus;
}
sInt32 ServerControl::RegisterForSystemPower ( void )
{
IONotificationPortRef pmNotificationPortRef;
CFRunLoopSourceRef pmNotificationRunLoopSource;
DBGLOG( kLogApplication, "RegisterForSystemPower(): " );
gPMKernelPort = IORegisterForSystemPower(this, &pmNotificationPortRef, dsPMNotificationHandler, &gPMDeregisterNotifier);
if (gPMKernelPort == nil || pmNotificationPortRef == nil)
{
ERRORLOG( kLogApplication, "RegisterForSystemPower(): IORegisterForSystemPower failed" );
}
else
{
pmNotificationRunLoopSource = IONotificationPortGetRunLoopSource(pmNotificationPortRef);
if (pmNotificationRunLoopSource == nil)
{
ERRORLOG( kLogApplication, "RegisterForSystemPower(): IONotificationPortGetRunLoopSource failed" );
gPMKernelPort = nil;
}
else
{
CFRunLoopAddSource(gServerRunLoop, pmNotificationRunLoopSource, kCFRunLoopCommonModes);
}
}
return (gPMKernelPort != nil) ? eDSNoErr : -1;
}
sInt32 ServerControl::UnRegisterForSystemPower ( void )
{
sInt32 ioResult = eDSNoErr;
DBGLOG( kLogApplication, "UnRegisterForSystemPower(): " );
if (gPMKernelPort != nil) {
gPMKernelPort = nil;
ioResult = (sInt32)IODeregisterForSystemPower(&gPMDeregisterNotifier);
if (ioResult != eDSNoErr)
{
DBGLOG1( kLogApplication, "UnRegisterForSystemPower(): IODeregisterForSystemPower failed, error= %d", ioResult );
}
}
return ioResult;
}
sInt32 ServerControl::HandleSystemWillSleep ( void )
{
sInt32 siResult = eDSNoErr;
uInt32 iterator = 0;
CServerPlugin *pPlugin = nil;
sHeader aHeader;
CPlugInList::sTableData *pPIInfo = nil;
SRVRLOG( kLogApplication, "Sleep Notification occurred.");
aHeader.fType = kHandleSystemWillSleep;
aHeader.fResult = eDSNoErr;
aHeader.fContextData = nil;
if ( gPlugins != nil )
{
pPlugin = gPlugins->Next( &iterator );
while (pPlugin != nil)
{
pPIInfo = gPlugins->GetPlugInInfo( iterator-1 );
if (pPIInfo->fState & kActive) {
siResult = eDSNoErr;
siResult = pPlugin->ProcessRequest( (void*)&aHeader );
if (siResult != eDSNoErr && siResult != eNotHandledByThisNode && siResult != eNotYetImplemented)
{
if (pPIInfo != nil)
{
ERRORLOG2( kLogApplication, "SystemWillSleep Notification in %s plugin returned error %d", pPIInfo->fName, siResult );
}
else
{
ERRORLOG1( kLogApplication, "SystemWillSleep Notification of unnamed plugin returned error %d", siResult );
}
}
}
pPlugin = gPlugins->Next( &iterator );
}
}
return siResult;
}
sInt32 ServerControl::HandleSystemWillPowerOn ( void )
{
sInt32 siResult = eDSNoErr;
uInt32 iterator = 0;
CServerPlugin *pPlugin = nil;
sHeader aHeader;
CPlugInList::sTableData *pPIInfo = nil;
SRVRLOG( kLogApplication, "Will Power On (Wake) Notification occurred.");
aHeader.fType = kHandleSystemWillPowerOn;
aHeader.fResult = eDSNoErr;
aHeader.fContextData = nil;
if ( gPlugins != nil )
{
pPlugin = gPlugins->Next( &iterator );
while (pPlugin != nil)
{
pPIInfo = gPlugins->GetPlugInInfo( iterator-1 );
if (pPIInfo->fState & kActive) {
siResult = eDSNoErr;
siResult = pPlugin->ProcessRequest( (void*)&aHeader );
if (siResult != eDSNoErr && siResult != eNotHandledByThisNode && siResult != eNotYetImplemented)
{
if (pPIInfo != nil)
{
ERRORLOG2( kLogApplication, "WillPowerOn Notification in %s plugin returned error %d", pPIInfo->fName, siResult );
}
else
{
ERRORLOG1( kLogApplication, "WillPowerOn Notification of unnamed plugin returned error %d", siResult );
}
}
}
pPlugin = gPlugins->Next( &iterator );
}
}
return siResult;
}
sInt32 ServerControl::HandleNetworkTransition ( void )
{
sInt32 siResult = eDSNoErr;
uInt32 iterator = 0;
CServerPlugin *pPlugin = nil;
sHeader aHeader;
CPlugInList::sTableData *pPIInfo = nil;
CServerPlugin *searchPlugin = nil;
uInt32 searchIterator = 0;
aHeader.fType = kHandleNetworkTransition;
aHeader.fResult = eDSNoErr;
aHeader.fContextData = nil;
SRVRLOG( kLogApplication, "Network transition occurred." );
gFirstNetworkUpAtBoot = true;
if ( gPlugins != nil )
{
pPlugin = gPlugins->Next( &iterator );
while (pPlugin != nil)
{
pPIInfo = gPlugins->GetPlugInInfo( iterator-1 );
if (pPIInfo->fState & kActive) {
if ( ::strcmp(pPIInfo->fName,"Search") != 0)
{
siResult = eDSNoErr;
siResult = pPlugin->ProcessRequest( (void*)&aHeader );
if (siResult != eDSNoErr)
{
if (pPIInfo != nil)
{
ERRORLOG2( kLogApplication, "Network transition in %s plugin returned error %d", pPIInfo->fName, siResult );
}
else
{
ERRORLOG1( kLogApplication, "Network transition of unnamed plugin returned error %d", siResult );
}
}
}
else
{
searchIterator = iterator;
searchPlugin = pPlugin;
}
}
pPlugin = gPlugins->Next( &iterator );
}
}
if (searchPlugin != nil)
{
siResult = eDSNoErr;
aHeader.fType = kHandleNetworkTransition;
siResult = searchPlugin->ProcessRequest( (void*)&aHeader );
if (siResult != eDSNoErr)
{
ERRORLOG1( kLogApplication, "Network transition in Search returned error %d", siResult );
}
}
HandleMultipleNetworkTransitionsForNIAutoSwitch();
return siResult;
}
sInt32 ServerControl::SetUpPeriodicTask ( void )
{
sInt32 siResult = eDSNoErr;
void *ptInfo = nil;
CFRunLoopTimerContext c = {0, (void*)ptInfo, NULL, NULL, PeriodicTaskCopyStringCallback};
CFRunLoopTimerRef timer = CFRunLoopTimerCreate( NULL,
CFAbsoluteTimeGetCurrent() + 120,
30,
0,
0,
DoPeriodicTask,
(CFRunLoopTimerContext*)&c);
CFRunLoopAddTimer(gServerRunLoop, timer, kCFRunLoopDefaultMode);
if (timer) CFRelease(timer);
return siResult;
}
void ServerControl::NodeSearchPolicyChanged( void )
{
void *ptInfo = nil;
gTimerMutex->Wait();
if (gServerRunLoop != nil)
{
if( fNSPCTimerRef != NULL )
{
DBGLOG1( kLogPlugin, "T[%X] ServerControl::NodeSearchPolicyChanged invalidating previous timer", pthread_self() );
CFRunLoopTimerInvalidate( fNSPCTimerRef );
CFRelease( fNSPCTimerRef );
fNSPCTimerRef = NULL;
}
ptInfo = (void *)this;
CFRunLoopTimerContext c = {0, (void*)ptInfo, NULL, NULL, SearchPolicyChangeCopyStringCallback};
fNSPCTimerRef = CFRunLoopTimerCreate( NULL,
CFAbsoluteTimeGetCurrent() + 2,
0,
0,
0,
DoSearchPolicyChange,
(CFRunLoopTimerContext*)&c);
CFRunLoopAddTimer(gServerRunLoop, fNSPCTimerRef, kCFRunLoopDefaultMode);
}
gTimerMutex->Signal();
}
void ServerControl::DoNodeSearchPolicyChange( void )
{
SCDynamicStoreRef store = NULL;
DBGLOG( kLogApplication, "DoNodeSearchPolicyChange" );
store = SCDynamicStoreCreate(NULL, fServiceNameString, NULL, NULL);
if (store != NULL)
{
if ( !SCDynamicStoreSetValue( store, CFSTR(kDSStdNotifySearchPolicyChanged), CFSTR("") ) )
{
ERRORLOG( kLogApplication, "Could not set the DirectoryService:SearchPolicyChangeToken in System Configuration" );
}
CFRelease(store);
store = NULL;
}
else
{
ERRORLOG( kLogApplication, "ServerControl::DoNodeSearchPolicyChange SCDynamicStoreCreate not yet available from System Configuration" );
}
LaunchKerberosAutoConfigTool();
}
void ServerControl::NotifySearchPolicyFoundNIParent( void )
{
SCDynamicStoreRef store = NULL;
DBGLOG( kLogApplication, "NotifySearchPolicyFoundNIParent" );
store = SCDynamicStoreCreate(NULL, fServiceNameString, NULL, NULL);
if (store != NULL)
{
if ( !SCDynamicStoreSetValue( store, CFSTR(kDSStdNotifySearchPolicyFoundNIParent), CFSTR("") ) )
{
ERRORLOG( kLogApplication, "Could not set the DirectoryService:NotifySearchPolicyFoundNIParent in System Configuration" );
}
CFRelease(store);
store = NULL;
}
else
{
ERRORLOG( kLogApplication, "ServerControl::NotifySearchPolicyFoundNIParent SCDynamicStoreCreate not yet available from System Configuration" );
}
}
void ServerControl::NotifyDirNodeAdded( const char* newNode )
{
SCDynamicStoreRef store = NULL;
if ( newNode != nil )
{
CFStringRef newNodeRef = CFStringCreateWithCString( NULL, newNode, kCFStringEncodingUTF8 );
if ( newNodeRef == NULL )
{
ERRORLOG1( kLogApplication, "Could not notify that dir node: (%s) was added due to an encoding problem", newNode );
}
else
{
store = SCDynamicStoreCreate(NULL, fServiceNameString, NULL, NULL);
if (store != NULL)
{
if ( !SCDynamicStoreSetValue( store, CFSTR(kDSStdNotifyDirectoryNodeAdded), newNodeRef ) )
{
ERRORLOG( kLogApplication, "Could not set the DirectoryService:NotifyDirNodeAdded in System Configuration" );
}
CFRelease(store);
store = NULL;
}
else
{
ERRORLOG( kLogApplication, "ServerControl::NotifyDirNodeAdded SCDynamicStoreCreate not yet available from System Configuration" );
}
CFRelease( newNodeRef );
newNodeRef = NULL;
}
}
}
void ServerControl::NotifyDirNodeDeleted( char* oldNode )
{
SCDynamicStoreRef store = NULL;
if ( oldNode != nil )
{
CFStringRef oldNodeRef = CFStringCreateWithCString( NULL, oldNode, kCFStringEncodingUTF8 );
if ( oldNodeRef == NULL )
{
ERRORLOG1( kLogApplication, "Could not notify that dir node: (%s) was deleted due to an encoding problem", oldNode );
}
else
{
store = SCDynamicStoreCreate(NULL, fServiceNameString, NULL, NULL);
if (store != NULL)
{
if ( !SCDynamicStoreSetValue( store, CFSTR(kDSStdNotifyDirectoryNodeDeleted), oldNodeRef ) )
{
ERRORLOG( kLogApplication, "Could not set the DirectoryService:NotifyDirNodeDeleted in System Configuration" );
}
CFRelease(store);
store = NULL;
}
else
{
ERRORLOG( kLogApplication, "ServerControl::NotifyDirNodeDeleted SCDynamicStoreCreate not yet available from System Configuration" );
}
CFRelease( oldNodeRef );
oldNodeRef = NULL;
}
}
}
#ifdef BUILD_IN_PERFORMANCE
void ServerControl::DeletePerfStatTable( void )
{
PluginPerformanceStats** table = fPerfTable;
uInt32 pluginCount = fPerfTableNumPlugins;
fPerfTable = NULL;
fPerfTableNumPlugins = 0;
if ( table )
{
for ( uInt32 i=0; i<pluginCount+1; i++ )
{
if ( table[i] )
{
free( table[i] );
table[i] = NULL;
}
}
free( table );
}
}
PluginPerformanceStats** ServerControl::CreatePerfStatTable( void )
{
DBGLOG( kLogPerformanceStats, "ServerControl::CreatePerfStatTable called\n" );
PluginPerformanceStats** table = NULL;
uInt32 pluginCount = gPlugins->GetPlugInCount();
if ( fPerfTable )
DeletePerfStatTable();
table = (PluginPerformanceStats**)calloc( sizeof(PluginPerformanceStats*), pluginCount+1 );
for ( uInt32 i=0; i<pluginCount; i++ )
{
table[i] = (PluginPerformanceStats*)calloc( sizeof(PluginPerformanceStats), 1 );
table[i]->pluginSignature = gPlugins->GetPlugInInfo(i)->fKey;
table[i]->pluginName = gPlugins->GetPlugInInfo(i)->fName;
}
table[pluginCount] = (PluginPerformanceStats*)calloc( sizeof(PluginPerformanceStats), 1 );
table[pluginCount]->pluginSignature = 0;
table[pluginCount]->pluginName = "Server";
fPerfTableNumPlugins = pluginCount;
fPerfTable = table;
return table;
}
double gLastDump =0;
#define kNumSecsBetweenDumps 60*2
void ServerControl::HandlePerformanceStats( uInt32 msgType, FourCharCode pluginSig, sInt32 siResult, sInt32 clientPID, double inTime, double outTime )
{
gPerformanceLoggingLock->Wait();
PluginPerformanceStats* curPluginStats = NULL;
uInt32 pluginCount = gPlugins->GetPlugInCount();
if ( !fPerfTable || fPerfTableNumPlugins != pluginCount )
{
fPerfTable = CreatePerfStatTable();
}
if ( !pluginSig )
curPluginStats = fPerfTable[pluginCount];
if ( fPerfTable[fLastPluginCalled]->pluginSignature == pluginSig )
curPluginStats = fPerfTable[fLastPluginCalled];
for ( uInt32 i=0; !curPluginStats && i<pluginCount; i++ )
{
if ( pluginSig == fPerfTable[i]->pluginSignature )
{
curPluginStats = fPerfTable[i];
fLastPluginCalled = i;
}
}
if ( curPluginStats )
{
PluginPerformanceAPIStat* curAPI = &(curPluginStats->apiStats[msgType]);
double duration = outTime-inTime;
curAPI->msgCnt++;
if ( siResult )
{
for( int i=kNumErrorsToTrack-1; i>0; i-- )
{
curAPI->lastNErrors[i].error = curAPI->lastNErrors[i-1].error;
curAPI->lastNErrors[i].clientPID = curAPI->lastNErrors[i-1].clientPID;
}
curAPI->lastNErrors[0].error = siResult;
curAPI->lastNErrors[0].clientPID = clientPID;
curAPI->errCnt++;
}
if ( curAPI->minTime == 0 || curAPI->minTime > duration )
curAPI->minTime = duration;
if ( curAPI->maxTime == 0 || curAPI->maxTime < duration )
curAPI->maxTime = duration;
curAPI->totTime += duration;
}
gPerformanceLoggingLock->Signal();
}
#define USEC_PER_HOUR (double)60*60*USEC_PER_SEC
#define USEC_PER_DAY (double)24*USEC_PER_HOUR
void ServerControl::LogStats( void )
{
PluginPerformanceStats* curPluginStats = NULL;
uInt32 pluginCount = fPerfTableNumPlugins;
char logBuf[1024];
char totTimeStr[256];
gPerformanceLoggingLock->Wait();
syslog( LOG_CRIT, "**Usage Stats**\n");
syslog( LOG_CRIT, "\tPlugin\tAPI\tMsgCnt\tErrCnt\tminTime (usec)\tmaxTime (usec)\taverageTime (usec)\ttotTime (usec|secs|hours|days)\tLast PID\tLast Error\tPrev PIDs/Errors\n" );
for ( uInt32 i=0; i<pluginCount+1; i++ ) {
if ( !fPerfTable[i] )
continue;
curPluginStats = fPerfTable[i];
for ( uInt32 j=0; j<kDSPlugInCallsEnd; j++ )
{
if ( curPluginStats->apiStats[j].msgCnt > 0 )
{
if ( curPluginStats->apiStats[j].totTime < USEC_PER_SEC )
sprintf( totTimeStr, "%0.f usecs", curPluginStats->apiStats[j].totTime );
else if ( curPluginStats->apiStats[j].totTime < USEC_PER_HOUR )
{
double time = curPluginStats->apiStats[j].totTime / USEC_PER_SEC;
sprintf( totTimeStr, "%0.4f secs", time );
}
else if ( curPluginStats->apiStats[j].totTime < USEC_PER_DAY )
{
double time = curPluginStats->apiStats[j].totTime / USEC_PER_HOUR;
sprintf( totTimeStr, "%0.4f hours", time );
}
else
{
double time = curPluginStats->apiStats[j].totTime / USEC_PER_DAY;
sprintf( totTimeStr, "%0.4f days", time );
}
sprintf( logBuf, "\t%s\t%s\t%ld\t%ld\t%.0f\t%0.f\t%0.f\t%s\t%ld/%ld\t%ld/%ld\t%ld/%ld\t%ld/%ld\t%ld/%ld\n",
curPluginStats->pluginName,
CRequestHandler::GetCallName(j),
curPluginStats->apiStats[j].msgCnt,
curPluginStats->apiStats[j].errCnt,
curPluginStats->apiStats[j].minTime,
curPluginStats->apiStats[j].maxTime,
(curPluginStats->apiStats[j].totTime/curPluginStats->apiStats[j].msgCnt),
totTimeStr,
curPluginStats->apiStats[j].lastNErrors[0].clientPID,
curPluginStats->apiStats[j].lastNErrors[0].error,
curPluginStats->apiStats[j].lastNErrors[1].clientPID,
curPluginStats->apiStats[j].lastNErrors[1].error,
curPluginStats->apiStats[j].lastNErrors[2].clientPID,
curPluginStats->apiStats[j].lastNErrors[2].error,
curPluginStats->apiStats[j].lastNErrors[3].clientPID,
curPluginStats->apiStats[j].lastNErrors[3].error,
curPluginStats->apiStats[j].lastNErrors[4].clientPID,
curPluginStats->apiStats[j].lastNErrors[4].error );
syslog( LOG_CRIT, logBuf );
}
}
}
gPerformanceLoggingLock->Signal();
}
#endif
void DoPeriodicTask(CFRunLoopTimerRef timer, void *info)
{
sInt32 siResult = eDSNoErr;
uInt32 iterator = 0;
CServerPlugin *pPlugin = nil;
CPlugInList::sTableData *pPIInfo = nil;
if ( gPlugins != nil )
{
pPlugin = gPlugins->Next( &iterator );
while (pPlugin != nil)
{
pPIInfo = gPlugins->GetPlugInInfo( iterator-1 );
if (pPIInfo->fState & kActive) {
siResult = pPlugin->PeriodicTask();
if (siResult != eDSNoErr)
{
if (pPIInfo != nil)
{
DBGLOG2( kLogApplication, "Periodic Task in %s plugin returned error %d", pPIInfo->fName, siResult );
}
else
{
DBGLOG1( kLogApplication, "Periodic Task of unnamed plugin returned error %d", siResult );
}
}
}
pPlugin = gPlugins->Next( &iterator );
}
}
return;
}
sInt32 ServerControl::FlushLookupDaemonCache ( void )
{
sInt32 siResult = eDSNoErr;
int i = 0;
int proc = 0;
char str[32];
mach_port_t port = MACH_PORT_NULL;
DBGLOG( kLogApplication, "Sending lookupd flushcache" );
_lu_running();
port = _lookupd_port(0);
if( port != MACH_PORT_NULL )
{
_lookup_link(port, "_invalidatecache", &proc);
_lookup_one(port, proc, NULL, 0, (char **)&str, &i);
}
return(siResult);
}
sInt32 ServerControl::FlushMemberDaemonCache ( void )
{
sInt32 siResult = eDSNoErr;
DBGLOG( kLogApplication, "Sending memberd flushcache" );
mbr_reset_cache();
return(siResult);
}
sInt32 ServerControl::NIAutoSwitchCheck ( void )
{
sInt32 siResult = eDSNoErr;
uInt32 iterator = 0;
CServerPlugin *pPlugin = nil;
sHeader aHeader;
CPlugInList::sTableData *pPIInfo = nil;
aHeader.fType = kCheckNIAutoSwitch;
aHeader.fResult = eDSNoErr;
aHeader.fContextData = nil;
gNodeList->WaitForAuthenticationSearchNode();
if ( gPlugins != nil )
{
pPlugin = gPlugins->Next( &iterator );
while (pPlugin != nil)
{
pPIInfo = gPlugins->GetPlugInInfo( iterator-1 );
if ( ( strcmp(pPIInfo->fName,"Search") == 0) && (pPIInfo->fState & kActive) )
{
siResult = pPlugin->ProcessRequest( (void*)&aHeader );
if (siResult == eDSContinue)
{
sInt32 unbindResult = UnbindToNetInfo();
if (unbindResult == eDSNoErr)
{
DBGLOG( kLogApplication, "NIAutoSwitchCheck(): NIAutoSwitch record found in NetInfo parent has directed addition of LDAP directory to the search policy" );
}
else
{
DBGLOG( kLogApplication, "NIAutoSwitchCheck(): NIAutoSwitch record found in NetInfo parent has directed addition of LDAP directory to the search policy but NetInfo Unbind failed" );
}
}
break;
}
pPlugin = gPlugins->Next( &iterator );
}
}
return(siResult);
}
sInt32 ServerControl::UnbindToNetInfo ( void )
{
sInt32 siResult = eUnknownServerError;
SCPreferencesRef scpRef = NULL;
bool scpStatus = false;
CFTypeRef cfTypeRef = NULL;
char *pCurrSet = nil;
char charArray[ 1024 ];
const char *NetInfoPath = "%s/Network/Global/NetInfo";
CFStringRef cfNetInfoKey = NULL;
const char *InactiveTag =
"<dict>\
<key>__INACTIVE__</key>\
<integer>1</integer>\
</dict>";
unsigned long uiDataLen = 0;
CFDataRef dataRef = NULL;
CFPropertyListRef plistRef = NULL;
CFDictionaryRef dictRef = NULL;
CFMutableDictionaryRef dictMutableRef = NULL;
scpRef = SCPreferencesCreate( NULL, CFSTR("NIAutoSwitch"), 0 );
if ( scpRef == NULL )
{
return(siResult);
}
cfTypeRef = SCPreferencesGetValue( scpRef, CFSTR( "CurrentSet" ) );
if ( cfTypeRef != NULL )
{
pCurrSet = (char *)CFStringGetCStringPtr( (CFStringRef)cfTypeRef, kCFStringEncodingMacRoman );
if ( pCurrSet != nil )
{
sprintf( charArray, NetInfoPath, pCurrSet );
}
}
else
{
sprintf( charArray, NetInfoPath, "/Sets/0" );
}
cfNetInfoKey = CFStringCreateWithCString( kCFAllocatorDefault, charArray, kCFStringEncodingMacRoman );
if (cfNetInfoKey != NULL)
{
dictRef = SCPreferencesPathGetValue( scpRef, cfNetInfoKey);
if (dictRef != NULL)
{
dictMutableRef = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, dictRef);
if ( dictMutableRef != NULL)
{
int intValue = 1;
CFNumberRef cfNumber = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &intValue);
CFDictionarySetValue( dictMutableRef, CFSTR( "__INACTIVE__"), cfNumber );
}
}
else
{
uiDataLen = strlen( InactiveTag );
dataRef = CFDataCreate( kCFAllocatorDefault, (const UInt8 *)InactiveTag, uiDataLen );
if ( dataRef != nil )
{
plistRef = CFPropertyListCreateFromXMLData( kCFAllocatorDefault, dataRef, kCFPropertyListMutableContainers, nil );
if ( plistRef != nil )
{
dictMutableRef = (CFMutableDictionaryRef)plistRef;
}
CFRelease( dataRef );
}
}
if (dictMutableRef != NULL) {
scpStatus = SCPreferencesPathSetValue( scpRef, cfNetInfoKey, dictMutableRef );
CFRelease( dictMutableRef );
}
CFRelease( cfNetInfoKey );
}
if (scpStatus)
{
scpStatus = SCPreferencesCommitChanges( scpRef );
if (scpStatus)
{
scpStatus = SCPreferencesApplyChanges( scpRef );
}
}
CFRelease( scpRef );
if (scpStatus) siResult = eDSNoErr;
return(siResult);
}
void ServerControl::HandleLookupDaemonFlushCache ( void )
{
void *ptInfo = nil;
uInt32 timeOffset = 2;
gTimerMutex->Wait();
fLookupDaemonFlushCacheRequestCount++;
if (gServerRunLoop != nil)
{
if( fLDFCTimerRef != NULL )
{
DBGLOG1( kLogPlugin, "T[%X] ServerControl::HandleLookupDaemonFlushCache invalidating previous timer", pthread_self() );
CFRunLoopTimerInvalidate( fLDFCTimerRef );
CFRelease( fLDFCTimerRef );
fLDFCTimerRef = NULL;
}
ptInfo = (void *)this;
CFRunLoopTimerContext c = {0, (void*)ptInfo, NULL, NULL, LookupDaemonFlushCacheCopyStringCallback};
if (fLookupDaemonFlushCacheRequestCount > kDSActOnThisNumberOfFlushRequests)
{
fLookupDaemonFlushCacheRequestCount = 0;
timeOffset = 0; }
fLDFCTimerRef = CFRunLoopTimerCreate( NULL,
CFAbsoluteTimeGetCurrent() + timeOffset,
0,
0,
0,
DoLookupDaemonFlushCache,
(CFRunLoopTimerContext*)&c);
CFRunLoopAddTimer(gServerRunLoop, fLDFCTimerRef, kCFRunLoopDefaultMode);
}
gTimerMutex->Signal();
}
void ServerControl::HandleMemberDaemonFlushCache ( void )
{
void *ptInfo = nil;
uInt32 timeOffset = 2;
gTimerMutex->Wait();
fMemberDaemonFlushCacheRequestCount++;
if (gServerRunLoop != nil)
{
if( fMDFCTimerRef != NULL )
{
DBGLOG1( kLogPlugin, "T[%X] ServerControl::HandleLookupDaemonFlushCache invalidating previous timer", pthread_self() );
CFRunLoopTimerInvalidate( fMDFCTimerRef );
CFRelease( fMDFCTimerRef );
fMDFCTimerRef = NULL;
}
ptInfo = (void *)this;
CFRunLoopTimerContext c = {0, (void*)ptInfo, NULL, NULL, MemberDaemonFlushCacheCopyStringCallback};
if (fMemberDaemonFlushCacheRequestCount > kDSActOnThisNumberOfFlushRequests)
{
fMemberDaemonFlushCacheRequestCount = 0;
timeOffset = 0; }
fMDFCTimerRef = CFRunLoopTimerCreate( NULL,
CFAbsoluteTimeGetCurrent() + timeOffset,
0,
0,
0,
DoMemberDaemonFlushCache,
(CFRunLoopTimerContext*)&c);
CFRunLoopAddTimer(gServerRunLoop, fMDFCTimerRef, kCFRunLoopDefaultMode);
}
gTimerMutex->Signal();
}
void ServerControl::HandleMultipleNetworkTransitionsForNIAutoSwitch ( void )
{
void *ptInfo = nil;
gTimerMutex->Wait();
if (gServerRunLoop != nil)
{
if( fNIASTimerRef != NULL )
{
DBGLOG1( kLogPlugin, "T[%X] ServerControl::HandleLookupDaemonFlushCache invalidating previous timer", pthread_self() );
CFRunLoopTimerInvalidate( fNIASTimerRef );
CFRelease( fNIASTimerRef );
fNIASTimerRef = NULL;
}
ptInfo = (void *)this;
CFRunLoopTimerContext c = {0, (void*)ptInfo, NULL, NULL, NetworkChangeNIAutoSwitchCopyStringCallback};
fNIASTimerRef = CFRunLoopTimerCreate( NULL,
CFAbsoluteTimeGetCurrent() + 11,
0,
0,
0,
DoNIAutoSwitchNetworkChange,
(CFRunLoopTimerContext*)&c);
CFRunLoopAddTimer(gServerRunLoop, fNIASTimerRef, kCFRunLoopDefaultMode);
}
gTimerMutex->Signal();
}
void ServerControl:: LaunchKerberosAutoConfigTool ( void )
{
sInt32 result = eDSNoErr;
mach_port_t mach_init_port = MACH_PORT_NULL;
result = bootstrap_look_up( bootstrap_port, "com.apple.KerberosAutoConfig", &mach_init_port );
if ( result != eDSNoErr )
{
syslog( LOG_ALERT, "Error with bootstrap_look_up for com.apple.KerberosAutoConfig on mach_init port: %s at: %d: Msg = %s\n", __FILE__, __LINE__, mach_error_string( result ) );
}
else
{
sIPCMsg aMsg;
aMsg.fHeader.msgh_bits = MACH_MSGH_BITS( MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND );
aMsg.fHeader.msgh_size = sizeof(sIPCMsg) - sizeof( mach_msg_audit_trailer_t );
aMsg.fHeader.msgh_id = 0;
aMsg.fHeader.msgh_remote_port = mach_init_port;
aMsg.fHeader.msgh_local_port = MACH_PORT_NULL;
aMsg.fMsgType = 0;
aMsg.fCount = 1;
aMsg.fPort = MACH_PORT_NULL;
aMsg.fPID = 0;
aMsg.fMsgID = 0;
aMsg.fOf = 1;
mach_msg((mach_msg_header_t *)&aMsg, MACH_SEND_MSG | MACH_SEND_TIMEOUT, aMsg.fHeader.msgh_size, 0, MACH_PORT_NULL, 1, MACH_PORT_NULL);
mach_port_destroy(mach_task_self(), mach_init_port);
mach_init_port = MACH_PORT_NULL;
}
}
sInt32 ServerControl::ResetDebugging ( void )
{
sInt32 siResult = eDSNoErr;
uInt32 uiDataSize = 0;
char *pData = nil;
CFile *pFile = nil;
struct stat statbuf;
CFDataRef dataRef = nil;
CFBooleanRef cfBool = false;
bool bDebugging = false;
bool bFileUsed = false;
if (gToggleDebugging)
{
gToggleDebugging = false;
if (gDebugLogging)
{
CLog::StopDebugLog();
gDebugLogging = false;
syslog(LOG_ALERT,"Debug Logging turned OFF after receiving USR1 signal.");
}
gDSFWCSBPDebugLogging = false;
}
else
{
gToggleDebugging = true;
siResult = ::stat( kDSDebugConfigFilePath, &statbuf );
if ( siResult == eDSNoErr )
{
pFile = new CFile( kDSDebugConfigFilePath );
if (pFile != nil)
{
if ( (pFile->is_open()) && (pFile->FileSize() > 0) )
{
pData = (char *)::calloc( 1, pFile->FileSize() + 1 );
if ( pData != nil )
{
uiDataSize = pFile->ReadBlock( pData, pFile->FileSize() );
dataRef = ::CFDataCreate( nil, (const uInt8 *)pData, uiDataSize );
if ( dataRef != nil )
{
CFPropertyListRef aPlistRef = 0;
CFDictionaryRef aDictRef = 0;
aPlistRef = ::CFPropertyListCreateFromXMLData( kCFAllocatorDefault, dataRef, kCFPropertyListImmutable, nil );
if ( aPlistRef != nil )
{
if ( ::CFDictionaryGetTypeID() == ::CFGetTypeID( aPlistRef ) )
{
bFileUsed = true;
aDictRef = (CFDictionaryRef)aPlistRef;
if ( CFDictionaryContainsKey( aDictRef, CFSTR( kXMLDSDebugLoggingKey ) ) )
{
cfBool= (CFBooleanRef)CFDictionaryGetValue( aDictRef, CFSTR( kXMLDSDebugLoggingKey ) );
if (cfBool != nil)
{
bDebugging = CFBooleanGetValue( cfBool );
if (gDebugLogging && !bDebugging)
{
CLog::StopDebugLog();
gDebugLogging = false;
syslog(LOG_ALERT,"Debug Logging turned OFF after receiving USR1 signal.");
}
else if (!gDebugLogging && bDebugging)
{
gDebugLogging = true;
CLog::StartDebugLog();
syslog(LOG_ALERT,"Debug Logging turned ON after receiving USR1 signal.");
}
}
}
else if (gDebugLogging)
{
CLog::StopDebugLog();
gDebugLogging = false;
syslog(LOG_ALERT,"Debug Logging turned OFF after receiving USR1 signal.");
}
if ( CFDictionaryContainsKey( aDictRef, CFSTR( kXMLDSCSBPDebugLoggingKey ) ) )
{
cfBool= (CFBooleanRef)CFDictionaryGetValue( aDictRef, CFSTR( kXMLDSCSBPDebugLoggingKey ) );
if (cfBool != nil)
{
gDSFWCSBPDebugLogging = CFBooleanGetValue( cfBool );
}
}
else
{
gDSFWCSBPDebugLogging = false;
}
aDictRef = 0;
}
CFRelease(aPlistRef);
}
CFRelease( dataRef );
dataRef = nil;
}
free( pData );
pData = nil;
}
}
delete( pFile );
pFile = nil;
}
}
if (!bFileUsed)
{
sInt32 result = eDSNoErr;
gDebugLogging = true;
CLog::StartDebugLog();
syslog(LOG_ALERT,"Debug Logging turned ON after receiving USR1 signal.");
uiDataSize = ::strlen( kDefaultDebugConfig );
dataRef = ::CFDataCreate( nil, (const uInt8 *)kDefaultDebugConfig, uiDataSize );
if ( dataRef != nil )
{
result = ::stat( kDSDebugConfigFilePath, &statbuf );
if (result != eDSNoErr)
{
result = ::stat( "/Library/Preferences", &statbuf );
if (result != eDSNoErr)
{
::mkdir( "/Library/Preferences", 0775 );
::chmod( "/Library/Preferences", 0775 ); }
result = ::stat( "/Library/Preferences/DirectoryService", &statbuf );
if (result != eDSNoErr)
{
::mkdir( "/Library/Preferences/DirectoryService", 0775 );
::chmod( "/Library/Preferences/DirectoryService", 0775 ); }
}
UInt8 *pData = (UInt8*)::calloc( CFDataGetLength(dataRef), 1 );
CFDataGetBytes( dataRef, CFRangeMake(0,CFDataGetLength(dataRef)), pData );
if ( (pData != nil) && (pData[0] != 0) )
{
try
{
CFile *pFile = new CFile( kDSDebugConfigFilePath, true );
if ( pFile != nil )
{
if ( pFile->is_open() )
{
pFile->seteof( 0 );
pFile->write( pData, CFDataGetLength(dataRef) );
::chmod( kDSDebugConfigFilePath, 0600 );
}
delete( pFile );
pFile = nil;
}
}
catch ( ... )
{
}
free(pData);
}
CFRelease( dataRef );
dataRef = nil;
}
}
}
return(siResult);
}