#include "CCachePlugin.h"
#include "CPlugInRef.h"
#include "CContinue.h"
#include "DSEventSemaphore.h"
#include "DirServices.h"
#include "DirServicesUtils.h"
#include "ServerModuleLib.h"
#include "DSUtils.h"
#include "COSUtils.h"
#include "PluginData.h"
#include "DSCThread.h"
#include "CLog.h"
#include "CAttributeList.h"
#include "CBuff.h"
#include "CDataBuff.h"
#include "ServerControl.h"
#include "CPlugInList.h"
#include "PrivateTypes.h"
#include "idna.h"
#include "Mbrd_MembershipResolver.h"
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h> //used for mkdir and stat
#include <mach/mach_time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <resolv.h>
#include <dns_util.h>
#include <dns_private.h>
#include <net/if.h>
#include <ifaddrs.h>
#include <notify.h>
#include <net/ethernet.h>
#include <syslog.h>
#include <sys/sysctl.h>
#include <DirectoryServiceCore/CSharedData.h>
#include <DirectoryService/DirServicesPriv.h>
#include <netdb_async.h>
#include <netinet/in.h>
#include <dispatch/dispatch.h>
#include <membershipPriv.h>
#include <vproc_priv.h>
static CPlugInRef *gCacheNodeRef = NULL;
static CContinue *gCacheNodeContinue = NULL;
static int32_t aaaa_cutoff_enabled = true;
static int gActiveThreadCount = 0;
static pthread_mutex_t gActiveThreadMutex = PTHREAD_MUTEX_INITIALIZER;
CCachePlugin *gCacheNode = NULL;
DSEventSemaphore gKickCacheRequests;
extern const char *lookupProcedures[];
extern CPlugInList *gPlugins;
extern dsBool gDSInstallDaemonMode;
extern bool gServerOS;
extern dsBool gDSInstallDaemonMode;
extern dsBool gDSLocalOnlyMode;
extern bool gCacheFlushDisabled;
const int kEnumerationCacheTime = 5;
const int kNegativeDNSCacheTime = 300; const int kNegativeCacheTime = 1800; const int kCacheTime = 3600; const int DNS_BUFFER_SIZE = 8192;
const int kDefaultTTLValue = -1;
#ifdef HANDLE_DNS_LOOKUPS
static pthread_t gActiveThreads[512];
static int gNotifyTokens[512];
static void* gInterruptTokens[512];
static bool gThreadAbandon[512];
static dns_handle_t gDNSHandles[512];
extern "C" {
uint32_t notify_register_plain( const char *name, int *out_token );
void res_interrupt_requests_enable(void);
void* res_init_interrupt_token(void);
void res_delete_interrupt_token( void* token );
void res_interrupt_request( void* token );
}
#endif
#pragma mark -
#pragma mark Cache Plugin
#pragma mark -
#ifdef HANDLE_DNS_LOOKUPS
struct sDNSQuery
{
sDNSLookup *fLookupEntry;
int fQueryIndex;
};
enum eResolveStates
{
kResolveStateCheckDomain = 1,
kResolveStateBuildExtraQueries,
kResolveStateDoGetHostname,
kResolveStateDoExtraQuery,
kResolveStateDone
};
void CancelDNSThreads( void );
inline void SetMaxTTL( int32_t &oldTTL, int32_t newTTL )
{
if ( newTTL >= 0 && (oldTTL < 0 || newTTL < oldTTL) )
oldTTL = newTTL;
}
#endif
void dsSetNodeCacheAvailability( char *inNodeName, int inAvailable )
{
int iCount = 0;
if ( gCacheNode != NULL ){
iCount = gCacheNode->UpdateNodeReachability( inNodeName, inAvailable );
}
iCount += Mbrd_SetNodeAvailability( inNodeName, inAvailable );
if ( iCount > 0 )
dsPostNodeEvent();
}
void dsFlushLibinfoCache( void )
{
if ( gCacheNode != NULL )
gCacheNode->EmptyCacheEntryType( CACHE_ENTRY_TYPE_ALL );
}
#ifdef HANDLE_DNS_LOOKUPS
static void DNSChangeCallBack(SCDynamicStoreRef aSCDStore, CFArrayRef changedKeys, void *callback_argument)
{
if ( gCacheNode != NULL )
gCacheNode->DNSConfigurationChanged();
}
#endif
CCachePlugin::CCachePlugin ( FourCharCode inSig, const char *inName ) : CServerPlugin(inSig, inName), fStatsLock("CCachePlugin::fStatsLock")
{
fDirRef = 0;
fSearchNodeRef = 0;
fNISNodeRef = 0;
fState = kUnknownState;
if ( gCacheNodeRef == NULL )
{
if (gServerOS)
{
gCacheNodeRef = new CPlugInRef( CCachePlugin::ContextDeallocProc, 1024 );
}
else
{
gCacheNodeRef = new CPlugInRef( CCachePlugin::ContextDeallocProc, 256 );
}
}
if ( gCacheNodeContinue == NULL )
{
gCacheNodeContinue = new CContinue( CCachePlugin::ContinueDeallocProc );
}
fLibinfoCache = new CCache( kCacheTime, 0 );
fNISQueue = dispatch_queue_create( "com.apple.DirectoryService.CCachePlugin.NISQueue", NULL );
fCheckNISQueue = dispatch_queue_create( "com.apple.DirectorYService.CCachePlugin.CheckNISQueue", NULL );
fCacheHits = 0;
fCacheMisses = 0;
fTotalCalls = 0;
fTotalCallTime = 0.0;
fFlushCount = 0;
#ifdef HANDLE_DNS_LOOKUPS
fUnqualifiedSRVAllowed = true;
fAlwaysDoAAAA = false;
bzero( &fCallsByFunction, sizeof(fCallsByFunction) );
bzero( &fCacheHitsByFunction, sizeof(fCacheHitsByFunction) );
bzero( &fCacheMissByFunction, sizeof(fCacheMissByFunction) );
dns_type_number( "CNAME", &fTypeCNAME );
dns_type_number( "A", &fTypeA );
dns_type_number( "AAAA", &fTypeAAAA );
dns_type_number( "SRV", &fTypeSRV );
dns_type_number( "PTR", &fTypePTR );
dns_type_number( "MX", &fTypeMX );
dns_class_number( "IN", &fClassIN );
bzero( gActiveThreads, sizeof(gActiveThreads) );
bzero( gNotifyTokens, sizeof(gNotifyTokens) );
bzero( gInterruptTokens, sizeof(gInterruptTokens) );
bzero( gThreadAbandon, sizeof(gThreadAbandon) );
bzero( gDNSHandles, sizeof(gDNSHandles) );
res_interrupt_requests_enable();
int iDoUnqualifiedSRV[] = { kResolveStateBuildExtraQueries,
kResolveStateDoGetHostname,
kResolveStateCheckDomain,
kResolveStateDone };
int iNoUnqualifiedSRV[] = { kResolveStateBuildExtraQueries,
kResolveStateDoGetHostname,
kResolveStateCheckDomain,
kResolveStateBuildExtraQueries,
kResolveStateDoExtraQuery,
kResolveStateDone };
if( fUnqualifiedSRVAllowed )
{
bcopy( iDoUnqualifiedSRV, fGetAddrStateEngine, sizeof(iDoUnqualifiedSRV) );
}
else
{
bcopy( iNoUnqualifiedSRV, fGetAddrStateEngine, sizeof(iNoUnqualifiedSRV) );
}
#endif
fLocalOnlyPIDs.insert( getpid() );
fPluginInitialized = false;
}
CCachePlugin::~CCachePlugin ( void )
{
if (fDirRef != 0)
{
if (fSearchNodeRef != 0)
{
dsCloseDirNode(fSearchNodeRef);
}
dsCloseDirService( fDirRef );
}
}
SInt32 CCachePlugin::Validate ( const char *inVersionStr, const UInt32 inSignature )
{
fPlugInSignature = inSignature;
fPluginInitialized = true;
return( eDSNoErr );
}
SInt32 CCachePlugin::PeriodicTask ( void )
{
return( eDSNoErr );
}
void CCachePlugin::EmptyCacheEntryType ( uint32_t inEntryType )
{
if (gDSInstallDaemonMode) return;
if (gCacheFlushDisabled == true) {
DbgLog(kLogPlugin, "CCachePlugin::EmptyCacheEntryType - skipping because cache flushes are disabled");
return;
}
if ( inEntryType == CACHE_ENTRY_TYPE_ALL )
{
fLibinfoCache->Flush();
DbgLog( kLogPlugin, "CCachePlugin::EmptyCacheEntryType - Request to empty all types - Flushing the cache" );
}
else
{
int iCount = fLibinfoCache->Sweep( inEntryType, false );
if( iCount > 0 )
DbgLog( kLogPlugin, "CCachePlugin::EmptyCacheEntryType - Flushed %d cache entries of type %X", iCount, inEntryType );
}
}
int CCachePlugin::UpdateNodeReachability( char *inNodeName, bool inState )
{
if ( gDSInstallDaemonMode == true || gDSLocalOnlyMode == true ) return 0;
int iCount = fLibinfoCache->UpdateAvailability( inNodeName, inState );
if( iCount > 0 )
{
DbgLog( kLogPlugin, "CCachePlugin::UpdateNodeReachability - Updated %d cache entries for <%s> to <%s>", iCount, inNodeName,
(inState ? "Available" : "Unavailable") );
}
return iCount;
}
#ifdef HANDLE_DNS_LOOKUPS
void CCachePlugin::DNSConfigurationChanged( void )
{
CancelDNSThreads();
int iCount = fLibinfoCache->Sweep( CACHE_ENTRY_TYPE_HOST, false );
DbgLog( kLogPlugin, "CCachePlugin::DNSConfigurationChanged - flushed %d DNS cache entries", iCount );
} #endif
SInt32 CCachePlugin::SetPluginState ( const UInt32 inState )
{
if ( inState & kActive )
{
WakeUpRequests();
}
return( eDSNoErr );
}
SInt32 CCachePlugin::Initialize ( void )
{
SInt32 siResult = eDSNoErr;
tDataBufferPtr dataBuff = NULL;
UInt32 nodeCount = 0;
tContextData context = NULL;
tDataListPtr nodeName = NULL;
try
{
siResult = dsVerifyDirRefNum(fDirRef);
if (siResult != eDSNoErr)
{
siResult = dsOpenDirService( &fDirRef );
if ( siResult != eDSNoErr ) throw( siResult );
dataBuff = dsDataBufferAllocate( fDirRef, 256 );
if ( dataBuff == NULL ) throw( (SInt32)eMemoryAllocError );
siResult = dsFindDirNodes( fDirRef, dataBuff, NULL, eDSAuthenticationSearchNodeName, &nodeCount, &context );
if ( siResult != eDSNoErr ) throw( siResult );
if ( nodeCount < 1 ) throw( eDSNodeNotFound );
siResult = dsGetDirNodeName( fDirRef, dataBuff, 1, &nodeName );
if ( siResult != eDSNoErr ) throw( siResult );
siResult = dsOpenDirNode( fDirRef, nodeName, &fSearchNodeRef );
if ( nodeName != NULL )
{
dsDataListDeallocate( fDirRef, nodeName );
DSFree( nodeName );
}
if ( siResult != eDSNoErr ) throw( siResult );
nodeName = dsBuildFromPath( fDirRef, "/BSD/local", "/" );
siResult = dsOpenDirNode( fDirRef, nodeName, &fFlatFileNodeRef );
if ( nodeName != NULL )
{
dsDataListDeallocate( fDirRef, nodeName );
DSFree( nodeName );
}
siResult = dsFindDirNodes( fDirRef, dataBuff, NULL, eDSLocalNodeNames, &nodeCount, &context );
if ( siResult != eDSNoErr ) throw( siResult );
if ( nodeCount < 1 ) throw( eDSNodeNotFound );
siResult = dsGetDirNodeName( fDirRef, dataBuff, 1, &nodeName );
if ( siResult != eDSNoErr ) throw( siResult );
siResult = dsOpenDirNode( fDirRef, nodeName, &fLocalNodeRef );
if ( nodeName != NULL )
{
dsDataListDeallocate( fDirRef, nodeName );
DSFree( nodeName );
}
SCDynamicStoreContext scContext = { 0, this, NULL, NULL, NULL };
SCDynamicStoreRef store = SCDynamicStoreCreateWithOptions( kCFAllocatorDefault, NULL, NULL, SearchPolicyChange, &scContext );
if ( store != NULL ) {
CFStringRef key = CFSTR(kDSStdNotifySearchPolicyChanged);
CFArrayRef notifyKeys = CFArrayCreate( kCFAllocatorDefault, (const void **)&key, 1, &kCFTypeArrayCallBacks );
SCDynamicStoreSetNotificationKeys( store, notifyKeys, NULL );
SCDynamicStoreSetDispatchQueue( store, fCheckNISQueue );
DSCFRelease( notifyKeys );
}
dispatch_sync( fCheckNISQueue, ^(void) { CheckSearchPolicyForNIS(); } );
if ( siResult != eDSNoErr ) throw( siResult );
__sync_bool_compare_and_swap( &gCacheNode, NULL, this );
}
nodeName = ::dsBuildFromPathPriv( kDSCacheNodeName , "/" );
if( nodeName == NULL ) throw( eDSAllocationFailed );
CServerPlugin::_RegisterNode( fPlugInSignature, nodeName, kCacheNodeType );
dsDataListDeallocate( fDirRef, nodeName );
DSFree( nodeName );
#ifdef HANDLE_DNS_LOOKUPS
checkAAAAstatus();
#endif
fState = kUnknownState;
fState += kInitialized;
fState += kActive;
}
catch( SInt32 err )
{
siResult = err;
fState = kUnknownState;
fState += kFailedToInit;
}
if ( dataBuff != NULL )
{
dsDataBufferDeAllocate( fDirRef, dataBuff );
dataBuff = NULL;
}
if ( nodeName != NULL )
{
dsDataListDeallocate( fDirRef, nodeName );
DSFree( nodeName );
}
return( siResult );
}
void CCachePlugin::SearchPolicyChange( SCDynamicStoreRef store,
CFArrayRef changedKeys,
void *info )
{
DbgLog( kLogNotice, "CCachePlugin::SearchPolicyChange - search policy change notification, looking for NIS" );
((CCachePlugin *) info)->CheckSearchPolicyForNIS();
}
void CCachePlugin::CheckSearchPolicyForNIS( void )
{
UInt32 uiCount = 0;
tAttributeListRef attrListRef = 0;
tAttributeValueListRef attrValueListRef = 0;
tContextData continueData = 0;
tDataBufferPtr pDataBuffer = NULL;
tDataListPtr pNodeInfoList = NULL;
tAttributeEntryPtr pAttrEntry = NULL;
tAttributeValueEntryPtr pAttrValueEntry = NULL;
tDirNodeReference nisNodeRef = 0;
tDirStatus siResult;
pNodeInfoList = dsBuildListFromStringsPriv( kDSNAttrSearchPath, NULL );
if ( pNodeInfoList == NULL ) return;
pDataBuffer = dsDataBufferAllocatePriv( 2048 );
do {
siResult = dsGetDirNodeInfo( fSearchNodeRef, pNodeInfoList, pDataBuffer, false, &uiCount, &attrListRef, &continueData );
if ( siResult == eDSBufferTooSmall ) {
UInt32 newSize = pDataBuffer->fBufferSize * 2;
dsDataBufferDeallocatePriv( pDataBuffer );
pDataBuffer = dsDataBufferAllocatePriv( newSize );
}
} while ( siResult == eDSBufferTooSmall );
if ( siResult != eDSNoErr ) goto cleanup;
siResult = dsGetAttributeEntry( fSearchNodeRef, pDataBuffer, attrListRef, 1, &attrValueListRef, &pAttrEntry );
if ( siResult != eDSNoErr ) goto cleanup;
for ( UInt32 aIndex = 1; fNISNodeRef == 0 && aIndex <= pAttrEntry->fAttributeValueCount; aIndex++ )
{
siResult = dsGetAttributeValue( fSearchNodeRef, pDataBuffer, aIndex, attrValueListRef, &pAttrValueEntry );
if ( siResult != eDSNoErr || pAttrValueEntry->fAttributeValueData.fBufferData == NULL) break;
if ( strncmp(pAttrValueEntry->fAttributeValueData.fBufferData, "/BSD", sizeof("/BSD")-1) == 0 &&
strcmp(pAttrValueEntry->fAttributeValueData.fBufferData, "/BSD/local") != 0 )
{
tDataListPtr nodeName = dsBuildFromPathPriv( pAttrValueEntry->fAttributeValueData.fBufferData, "/" );
if ( nodeName != NULL ) {
DbgLog( kLogInfo, "CCachePlugin::CheckSearchPolicyForNIS - NIS node detected as '%s'",
pAttrValueEntry->fAttributeValueData.fBufferData );
if ( dsOpenDirNode(fDirRef, nodeName, &nisNodeRef) == eDSNoErr ) {
DbgLog( kLogNotice, "CCachePlugin::CheckSearchPolicyForNIS - opening NIS node '%s'",
pAttrValueEntry->fAttributeValueData.fBufferData );
}
dsDataListDeallocatePriv( nodeName );
DSFree( nodeName );
}
}
dsDeallocAttributeValueEntry( fDirRef, pAttrValueEntry );
pAttrValueEntry = NULL;
}
cleanup:
dispatch_async( fNISQueue,
^(void) {
if ( fNISNodeRef != 0 ) {
dsCloseDirNode( fNISNodeRef );
}
fNISNodeRef = nisNodeRef;
} );
if ( pNodeInfoList != NULL ) {
dsDataListDeallocatePriv( pNodeInfoList );
DSFree( pNodeInfoList );
}
if ( attrListRef != 0 ) {
dsCloseAttributeList( attrListRef );
}
if ( attrValueListRef != 0 ) {
dsCloseAttributeValueList( attrValueListRef );
}
if ( pAttrEntry != NULL ) {
dsDeallocAttributeEntry( fDirRef, pAttrEntry );
pAttrEntry = NULL;
}
if ( continueData != 0 ) {
dsReleaseContinueData( fDirRef, continueData );
}
if ( pDataBuffer != NULL ) {
dsDataBufferDeallocatePriv( pDataBuffer );
pDataBuffer = NULL;
}
}
void CCachePlugin::WakeUpRequests ( void )
{
gKickCacheRequests.PostEvent();
}
void CCachePlugin::WaitForInit ( void )
{
gKickCacheRequests.WaitForEvent( (UInt32)(2 * 60 * kMilliSecsPerSec) );
}
SInt32 CCachePlugin::ProcessRequest ( void *inData )
{
SInt32 siResult = eDSNoErr;
char *pathStr = NULL;
try
{
if ( inData == NULL )
{
throw( (SInt32)ePlugInDataError );
}
if (((sHeader *)inData)->fType == kOpenDirNode)
{
if (((sOpenDirNode *)inData)->fInDirNodeName != NULL) {
pathStr = ::dsGetPathFromListPriv( ((sOpenDirNode *)inData)->fInDirNodeName, "/" );
if ( (pathStr != NULL) && (strncmp(pathStr, kDSCacheNodeName, 7) != 0) )
{
throw( (SInt32)eDSOpenNodeFailed);
}
}
}
if ( ((sHeader *)inData)->fType == kServerRunLoop )
{
if ( (((sHeader *)inData)->fContextData) != NULL )
{
#ifdef HANDLE_DNS_LOOKUPS
CFStringRef dnsKey = NULL; CFMutableArrayRef keys = NULL;
SCDynamicStoreRef store = NULL;
CFRunLoopSourceRef rls = NULL;
DbgLog( kLogApplication, "CCachePlugin::ProcessRequest registering for DNS Change Notifications" );
keys = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
dnsKey = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
CFArrayAppendValue(keys, dnsKey);
CFRelease(dnsKey);
store = SCDynamicStoreCreate(NULL, CFSTR("DirectoryService:CCachePlugin"), DNSChangeCallBack, NULL);
if (store != NULL)
{
SCDynamicStoreSetNotificationKeys(store, keys, NULL);
rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
if (rls != NULL)
{
CFRunLoopAddSource(CFRunLoopGetMain(), rls, kCFRunLoopDefaultMode);
CFRelease(rls);
rls = NULL;
}
else
{
syslog(LOG_ALERT, "CCachePlugin::ProcessRequest failed to create runloop source for DNS Notifications");
}
}
else
{
syslog(LOG_ALERT, "CCachePlugin::ProcessRequest failed to register for DNS Notifications");
}
DSCFRelease(keys);
DSCFRelease(store);
#endif
return (siResult);
}
}
else if( ((sHeader *)inData)->fType == kKerberosMutex )
{
return eDSNoErr;
}
WaitForInit();
if (fState == kUnknownState)
{
throw( (SInt32)ePlugInCallTimedOut );
}
if ( (fState & kFailedToInit) || !(fState & kInitialized) )
{
throw( (SInt32)ePlugInFailedToInitialize );
}
if ( (fState & kInactive) || !(fState & kActive) )
{
throw( (SInt32)ePlugInNotActive );
}
if ( ((sHeader *)inData)->fType == kHandleNetworkTransition )
{
EmptyCacheEntryType( CACHE_ENTRY_TYPE_NEGATIVE );
#ifdef HANDLE_DNS_LOOKUPS
checkAAAAstatus();
#endif
siResult = eDSNoErr;
}
else if (((sHeader *)inData)->fType == kHandleSystemWillPowerOn)
{
siResult = eDSNoErr; }
else
{
siResult = HandleRequest( inData );
}
}
catch( SInt32 err )
{
siResult = err;
}
DSFree( pathStr );
return( siResult );
}
SInt32 CCachePlugin::HandleRequest ( void *inData )
{
SInt32 siResult = eDSNoErr;
sHeader *pMsgHdr = NULL;
if ( !fPluginInitialized )
{
DbgLog( kLogPlugin, "CCachePlugin::HandleRequest called when CCachePlugin hasn't finished being initialized" );
return ePlugInInitError;
}
try
{
pMsgHdr = (sHeader *)inData;
switch ( pMsgHdr->fType )
{
case kOpenDirNode:
siResult = OpenDirNode( (sOpenDirNode *)inData );
break;
case kCloseDirNode:
siResult = CloseDirNode( (sCloseDirNode *)inData );
break;
case kGetDirNodeInfo:
siResult = GetDirNodeInfo( (sGetDirNodeInfo *)inData );
break;
case kGetRecordList:
siResult = GetRecordList( (sGetRecordList *)inData );
break;
case kReleaseContinueData:
siResult = ReleaseContinueData( (sReleaseContinueData *)inData );
break;
case kGetRecordEntry:
siResult = GetRecordEntry( (sGetRecordEntry *)inData );
break;
case kGetAttributeEntry:
siResult = GetAttributeEntry( (sGetAttributeEntry *)inData );
break;
case kGetAttributeValue:
siResult = GetAttributeValue( (sGetAttributeValue *)inData );
break;
case kDoAttributeValueSearch:
case kDoAttributeValueSearchWithData:
siResult = AttributeValueSearch( (sDoAttrValueSearchWithData *)inData );
break;
case kDoMultipleAttributeValueSearch:
case kDoMultipleAttributeValueSearchWithData:
siResult = MultipleAttributeValueSearch( (sDoMultiAttrValueSearchWithData *)inData );
break;
case kCloseAttributeList:
siResult = CloseAttributeList( (sCloseAttributeList *)inData );
break;
case kCloseAttributeValueList:
siResult = CloseAttributeValueList( (sCloseAttributeValueList *)inData );
break;
case kDoPlugInCustomCall:
siResult = DoPlugInCustomCall( (sDoPlugInCustomCall *)inData );
break;
case kServerRunLoop:
siResult = eDSNoErr; break;
default:
siResult = eNotHandledByThisNode;
break;
}
pMsgHdr->fResult = siResult;
}
catch( SInt32 err )
{
siResult = err;
}
catch ( ... )
{
siResult = ePlugInError;
}
return( siResult );
}
kvbuf_t* CCachePlugin::ProcessLookupRequest ( int inProcNumber, char* inData, int inCount, pid_t inPID )
{
kvbuf_t *outData = NULL;
kvbuf_t *buffer = (inCount != 0 ? kvbuf_init(inData, inCount) : NULL);
double startTime = dsTimestamp();
switch ( inProcNumber )
{
case kDSLUgetpwnam:
outData = DSgetpwnam( buffer, inPID );
break;
case kDSLUgetpwuuid:
outData = DSgetpwuuid( buffer, inPID );
break;
case kDSLUgetpwuid:
outData = DSgetpwuid( buffer, inPID );
break;
case kDSLUgetpwent:
outData = DSgetpwent();
break;
case kDSLUgetgrnam:
outData = DSgetgrnam( buffer, inPID );
break;
case kDSLUgetgrgid:
outData = DSgetgrgid( buffer, inPID );
break;
case kDSLUgetgrent:
outData = DSgetgrent();
break;
case kDSLUgetfsbyname:
outData = DSgetfsbyname( buffer );
break;
case kDSLUgetfsent:
outData = DSgetfsent( inPID );
break;
case kDSLUalias_getbyname: outData = DSgetaliasbyname( buffer );
break;
case kDSLUalias_getent: outData = DSgetaliasent();
break;
case kDSLUgetservbyname: outData = DSgetservbyname( buffer, inPID );
break;
case kDSLUgetservbyport: outData = DSgetservbyport( buffer, inPID );
break;
case kDSLUgetservent: outData = DSgetservent();
break;
case kDSLUgetprotobyname: outData = DSgetprotobyname( buffer, inPID );
break;
case kDSLUgetprotobynumber: outData = DSgetprotobynumber( buffer, inPID );
break;
case kDSLUgetprotoent: outData = DSgetprotoent();
break;
case kDSLUgetrpcbyname: outData = DSgetrpcbyname( buffer, inPID );
break;
case kDSLUgetrpcbynumber: outData = DSgetrpcbynumber( buffer, inPID );
break;
case kDSLUgetrpcent: outData = DSgetrpcent();
break;
case kDSLUgetnetent:
outData = DSgetnetent();
break;
case kDSLUgetnetbyname:
outData = DSgetnetbyname( buffer, inPID );
break;
case kDSLUgetnetbyaddr:
outData = DSgetnetbyaddr( buffer, inPID );
break;
case kDSLUinnetgr:
outData = DSinnetgr( buffer );
break;
case kDSLUgetnetgrent:
outData = DSgetnetgrent( buffer );
break;
case kDSLUflushcache:
DbgLog( kLogPlugin, "CCachePlugin::flushcache request" );
fLibinfoCache->Flush();
_vproc_send_signal_by_label( "com.apple.mDNSResponder", SIGHUP ); break;
case kDSLUflushentry:
break;
#ifdef HANDLE_DNS_LOOKUPS
case kDSLUgetaddrinfo:
outData = DSgetaddrinfo( buffer, inPID );
break;
case kDSLUgetnameinfo:
outData = DSgetnameinfo( buffer, inPID );
break;
#endif
case kDSLUgethostbyaddr:
outData = DSgethostbyaddr( buffer, inPID );
break;
case kDSLUgethostbyname:
outData = DSgethostbyname( buffer, inPID );
break;
case kDSLUgethostent:
outData = DSgethostent( buffer, inPID );
break;
case kDSLUgetmacbyname:
outData = DSgetmacbyname( buffer, inPID );
break;
case kDSLUgethostbymac:
outData = DSgethostbymac( buffer, inPID );
break;
#ifdef HANDLE_DNS_LOOKUPS
case kDSLUdns_proxy:
outData = DSdns_proxy( buffer, inPID );
break;
#endif
case kDSLUgethostbyname_service:
outData = DSgethostbyname_service( buffer, inPID );
break;
case kDSLUgetbootpbyhw:
outData = DSgetbootpbyhw( buffer, inPID );
break;
case kDSLUgetbootpbyaddr:
outData = DSgetbootpbyaddr( buffer, inPID );
break;
case kDSLUgetpwnam_ext:
outData = DSgetpwnam_ext( buffer, inPID );
break;
case kDSLUgetpwnam_initext:
DSgetpwnam_initext( buffer, inPID );
break;
case kDSLUgetgrnam_ext:
outData = DSgetgrnam_ext( buffer, inPID );
break;
case kDSLUgetgrnam_initext:
DSgetgrnam_initext( buffer, inPID );
break;
default:
break;
}
if( buffer != NULL )
{
kvbuf_free( buffer );
buffer = NULL;
}
if ( outData != NULL && outData->datalen == sizeof(uint32_t) )
{
switch ( inProcNumber )
{
#ifdef HANDLE_DNS_LOOKUPS
case kDSLUgetaddrinfo:
case kDSLUgetnameinfo:
#endif
case kDSLUgethostbyaddr:
case kDSLUgethostbyname:
break;
default:
kvbuf_free( outData );
outData = NULL;
break;
}
}
fStatsLock.WaitLock();
fTotalCallTime += dsTimestamp() - startTime;
fTotalCalls++;
fCallsByFunction[inProcNumber] += 1;
fStatsLock.SignalLock();
return( outData );
}
#pragma mark -
#pragma mark Cache Apply helper
#pragma mark -
struct sCacheDetail
{
CFMutableDictionaryRef fEntryMap;
CFMutableArrayRef fEntries;
CFIndex *fCounts;
time_t fNow;
int fIsAdmin;
};
static CFDateRef ConvertBSDTimeToCFDate( time_t inTime )
{
CFGregorianDate gregorianDate;
struct tm *bsdDate = gmtime( &inTime );
gregorianDate.second = bsdDate->tm_sec;
gregorianDate.minute = bsdDate->tm_min;
gregorianDate.hour = bsdDate->tm_hour;
gregorianDate.day = bsdDate->tm_mday;
gregorianDate.month = bsdDate->tm_mon + 1;
gregorianDate.year = bsdDate->tm_year + 1900;
return CFDateCreate( kCFAllocatorDefault, CFGregorianDateGetAbsoluteTime(gregorianDate, NULL) );
}
static void CacheDetails( void *key, void *value, void *context )
{
sCacheEntry *entry = (sCacheEntry *) value;
sCacheDetail *details = (sCacheDetail *) context;
CFNumberRef tempNumber = CFNumberCreate( kCFAllocatorDefault, kCFNumberLongType, &value );
CFStringRef cfKeyValue = CFStringCreateWithCStringNoCopy( kCFAllocatorDefault, (char *) key, kCFStringEncodingUTF8, kCFAllocatorNull );
CFMutableArrayRef cfKeys = (CFMutableArrayRef) CFDictionaryGetValue( details->fEntryMap, tempNumber );
if ( cfKeys != NULL ) {
if ( details->fEntries != NULL ) {
CFArrayAppendValue( cfKeys, cfKeyValue );
}
}
else {
if ( details->fIsAdmin == false && (entry->fFlags & CACHE_ENTRY_TYPE_HOST) != 0 ) {
goto cleanup;
}
CFIndex *counts = details->fCounts;
CFMutableDictionaryRef cfEntry = NULL;
if ( details->fEntries != NULL )
{
cfEntry = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
cfKeys = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
CFArrayAppendValue( cfKeys, cfKeyValue );
CFDictionarySetValue( cfEntry, CFSTR("Keys"), cfKeys );
CFRelease( cfKeys );
CFDictionarySetValue( details->fEntryMap, tempNumber, cfKeys );
sCacheValidation *valid_t = entry->fValidation;
if (valid_t != NULL)
{
CFMutableDictionaryRef validation = CFDictionaryCreateMutable( kCFAllocatorDefault, 2, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks );
if ( valid_t->fNode != NULL )
{
CFDictionarySetValue( validation, CFSTR("Name"), valid_t->fNode );
}
CFStringRef cfToken = CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR("%u"), valid_t->fToken );
CFStringRef cfRefs = CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR("%u"), valid_t->fRefCount );
CFDictionarySetValue( validation, CFSTR("Available"), (valid_t->fNodeAvailable ? kCFBooleanTrue : kCFBooleanFalse) );
CFDictionarySetValue( validation, CFSTR("Token"), cfToken );
CFDictionarySetValue( validation, CFSTR("Reference Count"), cfRefs );
CFRelease( cfToken );
CFRelease( cfRefs );
CFDictionarySetValue( cfEntry, CFSTR("Validation Information"), validation );
CFRelease( validation );
}
if ( entry->fTTL )
{
CFStringRef ttl2 = CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR("%u"), entry->fTTL );
CFDictionarySetValue( cfEntry, CFSTR("TTL"), ttl2 );
CFRelease( ttl2 );
}
CFDateRef cfBestBefore = ConvertBSDTimeToCFDate( entry->fBestBefore );
if (cfBestBefore)
{
CFDictionarySetValue( cfEntry, CFSTR("Best Before"), cfBestBefore );
CFRelease( cfBestBefore );
}
CFDateRef cfLastAccess = ConvertBSDTimeToCFDate( entry->fLastAccess );
if (cfLastAccess)
{
CFDictionarySetValue( cfEntry, CFSTR("Last Access"), cfLastAccess );
CFRelease( cfLastAccess );
}
CFStringRef hits = CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR("%u"), entry->fHits );
CFDictionarySetValue( cfEntry, CFSTR("Hits"), hits );
CFRelease( hits );
CFStringRef cfRefs = CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR("%u"), entry->fRefCount );
CFDictionarySetValue( cfEntry, CFSTR("Reference Count"), cfRefs );
CFRelease( cfRefs );
if (entry->fFlags & CACHE_ENTRY_TYPE_NEGATIVE) {
CFDictionarySetValue( cfEntry, CFSTR("Negative Entry"), kCFBooleanTrue );
}
CFArrayAppendValue( details->fEntries, cfEntry );
}
else
{
CFDictionarySetValue( details->fEntryMap, tempNumber, kCFNull );
}
switch( entry->fFlags & 0x00000FFF )
{
case CACHE_ENTRY_TYPE_USER:
if ( cfEntry != NULL ) CFDictionarySetValue( cfEntry, CFSTR("Type"), CFSTR("User") );
counts[0] += 1;
break;
case CACHE_ENTRY_TYPE_GROUP:
if ( cfEntry != NULL ) CFDictionarySetValue( cfEntry, CFSTR("Type"), CFSTR("Group") );
counts[1] += 1;
break;
case CACHE_ENTRY_TYPE_HOST:
if ( cfEntry != NULL ) CFDictionarySetValue( cfEntry, CFSTR("Type"), CFSTR("Host") );
counts[2] += 1;
break;
case CACHE_ENTRY_TYPE_SERVICE:
if ( cfEntry != NULL ) CFDictionarySetValue( cfEntry, CFSTR("Type"), CFSTR("Service") );
counts[3] += 1;
break;
case CACHE_ENTRY_TYPE_COMPUTER:
if ( cfEntry != NULL ) CFDictionarySetValue( cfEntry, CFSTR("Type"), CFSTR("Computer") );
counts[4] += 1;
break;
case CACHE_ENTRY_TYPE_MOUNT:
if ( cfEntry != NULL ) CFDictionarySetValue( cfEntry, CFSTR("Type"), CFSTR("Mount") );
counts[5] += 1;
break;
case CACHE_ENTRY_TYPE_ALIAS:
if ( cfEntry != NULL ) CFDictionarySetValue( cfEntry, CFSTR("Type"), CFSTR("Alias") );
counts[6] += 1;
break;
case CACHE_ENTRY_TYPE_PROTOCOL:
if ( cfEntry != NULL ) CFDictionarySetValue( cfEntry, CFSTR("Type"), CFSTR("Protocol") );
counts[7] += 1;
break;
case CACHE_ENTRY_TYPE_RPC:
if ( cfEntry != NULL ) CFDictionarySetValue( cfEntry, CFSTR("Type"), CFSTR("RPC") );
counts[8] += 1;
break;
case CACHE_ENTRY_TYPE_NETWORK:
if ( cfEntry != NULL ) CFDictionarySetValue( cfEntry, CFSTR("Type"), CFSTR("Network") );
counts[9] += 1;
break;
default:
break;
}
DSCFRelease( cfEntry );
}
cleanup:
DSCFRelease( tempNumber );
DSCFRelease( cfKeyValue );
}
#pragma mark -
#pragma mark DS API Service Routines - Clients using Cache Node directly
#pragma mark -
SInt32 CCachePlugin::OpenDirNode ( sOpenDirNode *inData )
{
SInt32 siResult = eDSOpenNodeFailed;
char *pathStr = NULL;
sCacheContextData *pContext = NULL;
if ( inData != NULL )
{
pathStr = ::dsGetPathFromListPriv( inData->fInDirNodeName, "/" );
if ( ( pathStr != NULL ) && ( ::strcmp( pathStr, kDSCacheNodeName ) == 0 ) )
{
pContext = MakeContextData();
if (pContext != NULL)
{
pContext->fNodeName = pathStr;
pContext->fUID = inData->fInUID;
pContext->fEffectiveUID = inData->fInEffectiveUID;
gCacheNodeRef->AddItem( inData->fOutNodeRef, pContext );
siResult = eDSNoErr;
}
}
}
return( siResult );
}
SInt32 CCachePlugin::CloseDirNode ( sCloseDirNode *inData )
{
SInt32 siResult = eDSNoErr;
sCacheContextData *pContext = NULL;
try
{
pContext = (sCacheContextData *) gCacheNodeRef->GetItemData( inData->fInNodeRef );
if ( pContext == NULL ) throw( (SInt32)eDSInvalidNodeRef );
gCacheNodeRef->RemoveItem( inData->fInNodeRef );
gCacheNodeContinue->RemovePointersForRefNum( inData->fInNodeRef );
}
catch( SInt32 err )
{
siResult = err;
}
return( siResult );
}
SInt32 CCachePlugin::GetDirNodeInfo ( sGetDirNodeInfo *inData )
{
SInt32 siResult = eDSNoErr;
UInt32 uiOffset = 0;
UInt32 uiCntr = 1;
UInt32 uiAttrCnt = 0;
CAttributeList *inAttrList = NULL;
char *pAttrName = NULL;
char *pData = NULL;
sCacheContextData *pAttrContext = NULL;
CBuff outBuff;
sCacheContextData *pContext = NULL;
CDataBuff *aRecData = NULL;
CDataBuff *aAttrData = NULL;
CDataBuff *aTmpData = NULL;
UInt32 cacheNodeNameBufLen = 0;
SInt32 buffResult = eDSNoErr;
try
{
if ( inData == NULL ) throw( (SInt32)eMemoryError );
pContext = (sCacheContextData *)gCacheNodeRef->GetItemData( inData->fInNodeRef );
if ( pContext == NULL ) throw( (SInt32)eDSInvalidNodeRef );
inAttrList = new CAttributeList( inData->fInDirNodeInfoTypeList );
if ( inAttrList == NULL ) throw( (SInt32)eDSNullNodeInfoTypeList );
if (inAttrList->GetCount() == 0) throw( (SInt32)eDSEmptyNodeInfoTypeList );
siResult = outBuff.Initialize( inData->fOutDataBuff, true );
if ( siResult != eDSNoErr ) throw( siResult );
siResult = outBuff.SetBuffType( 'StdA' );
if ( siResult != eDSNoErr ) throw( siResult );
aRecData = new CDataBuff();
if ( aRecData == nil ) throw( (SInt32) eMemoryError );
aAttrData = new CDataBuff();
if ( aAttrData == nil ) throw( (SInt32) eMemoryError );
aTmpData = new CDataBuff();
if ( aTmpData == nil ) throw( (SInt32) eMemoryError );
aRecData->AppendShort( ::strlen( "dsRecTypeStandard:CacheNodeInfo" ) );
aRecData->AppendString( "dsRecTypeStandard:CacheNodeInfo" );
if (pContext->fNodeName != NULL)
{
cacheNodeNameBufLen = strlen( pContext->fNodeName );
aRecData->AppendShort( cacheNodeNameBufLen );
cacheNodeNameBufLen += 2;
aRecData->AppendString( pContext->fNodeName );
}
else
{
aRecData->AppendShort( ::strlen( "CacheNodeInfo" ) );
aRecData->AppendString( "CacheNodeInfo" );
cacheNodeNameBufLen = 15; }
while ( inAttrList->GetAttribute( uiCntr++, &pAttrName ) == eDSNoErr )
{
if ( (::strcmp( pAttrName, kDSAttributesAll ) == 0) ||
(::strcmp( pAttrName, kDS1AttrReadOnlyNode ) == 0) )
{
uiAttrCnt++;
buffResult = dsCDataBuffFromAttrTypeAndStringValue( aAttrData, aTmpData, inData->fInAttrInfoOnly, kDS1AttrReadOnlyNode, "ReadOnly" );
}
if ( strcmp( pAttrName, "dsAttrTypeNative:LibinfoCacheOverview" ) == 0 || strcmp( pAttrName, "dsAttrTypeNative:LibinfoCacheDetails" ) == 0 )
{
CFMutableDictionaryRef cfInformation = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks );
CFMutableArrayRef cfEntries = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
CFStringRef ttl = CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR("%u"), fLibinfoCache->fCacheTTL );
CFDictionarySetValue( cfInformation, CFSTR("Default TTL"), ttl );
CFRelease( ttl );
CFStringRef policy_flags = CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR("%u"), fLibinfoCache->fPolicyFlags );
CFDictionarySetValue( cfInformation, CFSTR("Policy Flags"), policy_flags );
CFRelease( policy_flags );
CFDictionarySetValue( cfInformation, CFSTR("AAAA Queries"),
(aaaa_cutoff_enabled ? CFSTR("Disabled (link-local IPv6 addresses)") : CFSTR("Enabled")) );
CFStringRef typesStr[] = { CFSTR("User"), CFSTR("Group"), CFSTR("Host"), CFSTR("Service"), CFSTR("Computer"),
CFSTR("Mount"), CFSTR("Alias"), CFSTR("Protocol"), CFSTR("RPC"), CFSTR("Network") };
uint32_t cacheTypes[] = { CACHE_ENTRY_TYPE_USER, CACHE_ENTRY_TYPE_GROUP, CACHE_ENTRY_TYPE_HOST, CACHE_ENTRY_TYPE_SERVICE,
CACHE_ENTRY_TYPE_COMPUTER, CACHE_ENTRY_TYPE_MOUNT, CACHE_ENTRY_TYPE_ALIAS, CACHE_ENTRY_TYPE_PROTOCOL,
CACHE_ENTRY_TYPE_RPC, CACHE_ENTRY_TYPE_NETWORK };
int32_t typeCnt = sizeof(cacheTypes) / sizeof(uint32_t);
CFIndex counts[typeCnt];
uint32_t total = 0;
uuid_t uu;
bzero( counts, sizeof(counts) );
sCacheDetail details = {
fEntryMap : CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ),
fEntries : NULL,
fCounts : counts,
fNow : time( NULL ),
fIsAdmin : (pContext->fEffectiveUID == 0)
};
if ( pContext->fEffectiveUID != 0 && mbr_uid_to_uuid(pContext->fEffectiveUID, uu) == 0 ) {
mbr_check_membership_by_id( uu, 80, &details.fIsAdmin );
}
if ( strcmp( pAttrName, "dsAttrTypeNative:LibinfoCacheDetails" ) == 0 )
{
details.fEntries = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
CFDictionarySetValue( cfInformation, CFSTR("Entries"), details.fEntries );
}
fLibinfoCache->ApplyFunction( CacheDetails, &details );
total = CFDictionaryGetCount( details.fEntryMap );
DSCFRelease( details.fEntryMap );
DSCFRelease( details.fEntries );
CFMutableDictionaryRef cfCounts = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks );
CFDictionarySetValue( cfInformation, CFSTR("Counts By Type"), cfCounts );
CFRelease( cfCounts );
for ( int ii = 0; ii < typeCnt; ii++ )
{
if ( counts[ii] > 0 )
{
CFNumberRef cfNumber = CFNumberCreate( kCFAllocatorDefault, kCFNumberCFIndexType, &counts[ii] );
CFDictionarySetValue( cfCounts, typesStr[ii], cfNumber );
CFRelease( cfNumber );
}
}
CFStringRef cur_size = CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR("%u"), total );
CFDictionarySetValue( cfInformation, CFSTR("Cache Size"), cur_size );
CFRelease( cur_size );
CFDataRef cfData = CFPropertyListCreateXMLData( kCFAllocatorDefault, cfInformation );
uiAttrCnt++;
buffResult = dsCDataBuffFromAttrTypeAndData( aAttrData, aTmpData, inData->fInAttrInfoOnly, pAttrName,
(const char *) CFDataGetBytePtr(cfData), (UInt32) CFDataGetLength(cfData) );
DSCFRelease( cfEntries );
DSCFRelease( cfInformation );
DSCFRelease( cfData );
}
if ( strcmp( pAttrName, "dsAttrTypeNative:Statistics" ) == 0 )
{
uiAttrCnt++;
CFMutableArrayRef cfStats = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
CFMutableDictionaryRef cfGlobalStats = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks );
fStatsLock.WaitLock();
double averageTime = 0.0;
if( fTotalCalls > 0 )
{
averageTime = (fTotalCallTime / (double) fTotalCalls) / (double) USEC_PER_SEC; }
CFStringRef cfCacheHits = CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR("%lld"), fCacheHits );
CFStringRef cfCacheMisses = CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR("%lld"), fCacheMisses );
CFStringRef cfTotalCalls = CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR("%lld"), fTotalCalls );
CFStringRef cfAverageCall = CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR("%f"), averageTime );
CFDictionarySetValue( cfGlobalStats, CFSTR("Category"), CFSTR("Global Statistics") );
CFDictionarySetValue( cfGlobalStats, CFSTR("Cache Hits"), cfCacheHits );
CFDictionarySetValue( cfGlobalStats, CFSTR("Cache Misses"), cfCacheMisses );
CFDictionarySetValue( cfGlobalStats, CFSTR("Total External Calls"), cfTotalCalls );
CFDictionarySetValue( cfGlobalStats, CFSTR("Average Call Time"), cfAverageCall );
DSCFRelease( cfCacheHits );
DSCFRelease( cfCacheMisses );
DSCFRelease( cfTotalCalls );
DSCFRelease( cfAverageCall );
CFArrayAppendValue( cfStats, cfGlobalStats );
DSCFRelease( cfGlobalStats );
CFMutableArrayRef cfProcedureStats = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
CFMutableDictionaryRef cfTempDict = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks );
CFDictionarySetValue( cfTempDict, CFSTR("subValues"), cfProcedureStats );
CFDictionarySetValue( cfTempDict, CFSTR("Category"), CFSTR("Procedure Statistics") );
CFArrayAppendValue( cfStats, cfTempDict );
DSCFRelease( cfTempDict );
for( int ii = 1; ii < kDSLUlastprocnum; ii++ )
{
CFStringRef cfProcedure;
cfTempDict = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks );
cfProcedure = CFStringCreateWithCString( kCFAllocatorDefault, lookupProcedures[ii], kCFStringEncodingUTF8 );
cfCacheHits = CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR("%lld"), fCacheHitsByFunction[ii] );
cfCacheMisses = CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR("%lld"), fCacheMissByFunction[ii] );
cfTotalCalls = CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR("%lld"), fCallsByFunction[ii] );
CFDictionarySetValue( cfTempDict, CFSTR("Category"), cfProcedure );
CFDictionarySetValue( cfTempDict, CFSTR("Cache Hits"), cfCacheHits );
CFDictionarySetValue( cfTempDict, CFSTR("Cache Misses"), cfCacheMisses );
CFDictionarySetValue( cfTempDict, CFSTR("Total Calls"), cfTotalCalls );
CFArrayAppendValue( cfProcedureStats, cfTempDict );
DSCFRelease( cfCacheHits );
DSCFRelease( cfCacheMisses );
DSCFRelease( cfTotalCalls );
DSCFRelease( cfProcedure );
DSCFRelease( cfTempDict );
}
DSCFRelease( cfProcedureStats );
fStatsLock.SignalLock();
CFDataRef cfStatData = CFPropertyListCreateXMLData( kCFAllocatorDefault, cfStats );
buffResult = dsCDataBuffFromAttrTypeAndData( aAttrData, aTmpData, inData->fInAttrInfoOnly, "dsAttrTypeNative:Statistics",
(const char *) CFDataGetBytePtr(cfStatData), (UInt32) CFDataGetLength(cfStatData) );
DSCFRelease( cfStatData );
DSCFRelease( cfStats );
}
}
aRecData->AppendShort( uiAttrCnt );
if (uiAttrCnt > 0)
{
aRecData->AppendBlock( aAttrData->GetData(), aAttrData->GetLength() );
}
outBuff.AddData( aRecData->GetData(), aRecData->GetLength() );
inData->fOutAttrInfoCount = uiAttrCnt;
pData = outBuff.GetDataBlock( 1, &uiOffset );
if ( pData != NULL )
{
pAttrContext = MakeContextData();
if ( pAttrContext == nil ) throw( (SInt32) eMemoryAllocError );
pAttrContext->offset = uiOffset + 36 + cacheNodeNameBufLen;
gCacheNodeRef->AddItem( inData->fOutAttrListRef, pAttrContext );
}
else
{
siResult = eDSBufferTooSmall;
}
inData->fOutDataBuff->fBufferLength = inData->fOutDataBuff->fBufferSize;
}
catch( SInt32 err )
{
siResult = err;
}
DSDelete( inAttrList );
DSDelete( aRecData );
DSDelete( aAttrData );
DSDelete( aTmpData );
return( siResult );
}
SInt32 CCachePlugin::GetRecordList ( sGetRecordList *inData )
{
SInt32 siResult = eDSNoErr;
sCacheContinueData *pContinue = NULL;
sCacheContextData *pContext = NULL;
tContextData uiContinue = 0;
try
{
pContext = (sCacheContextData *)gCacheNodeRef->GetItemData( inData->fInNodeRef );
if ( pContext == NULL ) throw( (SInt32)eDSInvalidNodeRef );
if ( inData->fIOContinueData == 0 )
{
pContinue = (sCacheContinueData *)::calloc( 1, sizeof( sCacheContinueData ) );
if ( pContinue == NULL ) throw( (SInt32)eMemoryAllocError );
uiContinue = gCacheNodeContinue->AddPointer( pContinue, inData->fInNodeRef );
pContinue->fDirRef = fDirRef;
pContinue->fNodeRef= fSearchNodeRef;
pContinue->fContinue = NULL;
pContinue->fLimitRecSearch = 0;
if (inData->fOutRecEntryCount >= 0)
{
pContinue->fLimitRecSearch = inData->fOutRecEntryCount;
}
}
else
{
pContinue = (sCacheContinueData *) gCacheNodeContinue->GetPointer( inData->fIOContinueData );
if ( pContinue == NULL ) throw( (SInt32)eDSInvalidContinueData );
uiContinue = inData->fIOContinueData;
}
siResult = dsGetRecordList( pContinue->fNodeRef,
inData->fInDataBuff,
inData->fInRecNameList,
inData->fInPatternMatch,
inData->fInRecTypeList,
inData->fInAttribTypeList,
inData->fInAttribInfoOnly,
&inData->fOutRecEntryCount,
&pContinue->fContinue );
if (pContinue->fContinue != 0)
{
inData->fIOContinueData = uiContinue;
}
else
{
gCacheNodeContinue->RemoveContext( uiContinue );
inData->fIOContinueData = 0;
}
}
catch( SInt32 err )
{
siResult = err;
}
return( siResult );
}
SInt32 CCachePlugin::AttributeValueSearch ( sDoAttrValueSearchWithData *inData )
{
SInt32 siResult = eDSNoErr;
sCacheContinueData *pContinue = NULL;
sCacheContextData *pContext = NULL;
tContextData uiContinue = 0;
try
{
pContext = (sCacheContextData *)gCacheNodeRef->GetItemData( inData->fInNodeRef );
if ( pContext == NULL ) throw( (SInt32)eDSInvalidNodeRef );
if ( inData->fIOContinueData == 0 )
{
pContinue = (sCacheContinueData *)::calloc( 1, sizeof( sCacheContinueData ) );
if ( pContinue == NULL ) throw( (SInt32)eMemoryAllocError );
uiContinue = gCacheNodeContinue->AddPointer( pContinue, inData->fInNodeRef );
pContinue->fDirRef = fDirRef;
pContinue->fNodeRef= fSearchNodeRef;
pContinue->fContinue = NULL;
pContinue->fLimitRecSearch = 0;
if (inData->fOutMatchRecordCount >= 0)
{
pContinue->fLimitRecSearch = inData->fOutMatchRecordCount;
}
}
else
{
pContinue = (sCacheContinueData *) gCacheNodeContinue->GetPointer( inData->fIOContinueData );
if ( pContinue == NULL ) throw( (SInt32)eDSInvalidContinueData );
uiContinue = inData->fIOContinueData;
}
if ( inData->fType == kDoAttributeValueSearchWithData )
{
siResult = ::dsDoAttributeValueSearchWithData(
pContinue->fNodeRef,
inData->fOutDataBuff,
inData->fInRecTypeList,
inData->fInAttrType,
inData->fInPattMatchType,
inData->fInPatt2Match,
inData->fInAttrTypeRequestList,
inData->fInAttrInfoOnly,
&inData->fOutMatchRecordCount,
&pContinue->fContinue );
}
else
{
siResult = ::dsDoAttributeValueSearch( pContinue->fNodeRef,
inData->fOutDataBuff,
inData->fInRecTypeList,
inData->fInAttrType,
inData->fInPattMatchType,
inData->fInPatt2Match,
&inData->fOutMatchRecordCount,
&pContinue->fContinue );
}
if (pContinue->fContinue != 0)
{
inData->fIOContinueData = uiContinue;
}
else
{
gCacheNodeContinue->RemoveContext( uiContinue );
inData->fIOContinueData = 0;
}
}
catch( SInt32 err )
{
siResult = err;
}
return( siResult );
}
SInt32 CCachePlugin::MultipleAttributeValueSearch ( sDoMultiAttrValueSearchWithData *inData )
{
SInt32 siResult = eDSNoErr;
sCacheContinueData *pContinue = NULL;
sCacheContextData *pContext = NULL;
tContextData uiContinue = 0;
try
{
pContext = (sCacheContextData *)gCacheNodeRef->GetItemData( inData->fInNodeRef );
if ( pContext == NULL ) throw( (SInt32)eDSInvalidNodeRef );
if ( inData->fIOContinueData == 0 )
{
pContinue = (sCacheContinueData *)::calloc( 1, sizeof( sCacheContinueData ) );
if ( pContinue == NULL ) throw( (SInt32)eMemoryAllocError );
uiContinue = gCacheNodeContinue->AddPointer( pContinue, inData->fInNodeRef );
pContinue->fDirRef = fDirRef;
pContinue->fNodeRef= fSearchNodeRef;
pContinue->fContinue = NULL;
pContinue->fLimitRecSearch = 0;
if (inData->fOutMatchRecordCount >= 0)
{
pContinue->fLimitRecSearch = inData->fOutMatchRecordCount;
}
}
else
{
pContinue = (sCacheContinueData *) gCacheNodeContinue->GetPointer( inData->fIOContinueData );
if ( pContinue == NULL ) throw( (SInt32)eDSInvalidContinueData );
uiContinue = inData->fIOContinueData;
}
if ( inData->fType == kDoMultipleAttributeValueSearchWithData )
{
siResult = ::dsDoMultipleAttributeValueSearchWithData(
pContinue->fNodeRef,
inData->fOutDataBuff,
inData->fInRecTypeList,
inData->fInAttrType,
inData->fInPattMatchType,
inData->fInPatterns2MatchList,
inData->fInAttrTypeRequestList,
inData->fInAttrInfoOnly,
&inData->fOutMatchRecordCount,
&pContinue->fContinue );
}
else
{
siResult = ::dsDoMultipleAttributeValueSearch(
pContinue->fNodeRef,
inData->fOutDataBuff,
inData->fInRecTypeList,
inData->fInAttrType,
inData->fInPattMatchType,
inData->fInPatterns2MatchList,
&inData->fOutMatchRecordCount,
&pContinue->fContinue );
}
if (pContinue->fContinue != 0)
{
inData->fIOContinueData = uiContinue;;
}
else
{
gCacheNodeContinue->RemoveContext( uiContinue );
inData->fIOContinueData = 0;
}
}
catch( SInt32 err )
{
siResult = err;
}
return( siResult );
}
SInt32 CCachePlugin::GetRecordEntry ( sGetRecordEntry *inData )
{
SInt32 siResult = eDSNoErr;
UInt32 uiIndex = 0;
UInt32 uiCount = 0;
UInt32 uiOffset = 0;
UInt32 uberOffset = 0;
char *pData = NULL;
tRecordEntryPtr pRecEntry = NULL;
sCacheContextData *pContext = NULL;
CBuff inBuff;
UInt32 offset = 0;
UInt16 usTypeLen = 0;
char *pRecType = NULL;
UInt16 usNameLen = 0;
char *pRecName = NULL;
UInt16 usAttrCnt = 0;
UInt32 buffLen = 0;
try
{
if ( inData == NULL ) throw( (SInt32)eMemoryError );
if ( inData->fInOutDataBuff == NULL ) throw( (SInt32)eDSEmptyBuffer );
if (inData->fInOutDataBuff->fBufferSize == 0) throw( (SInt32)eDSEmptyBuffer );
siResult = inBuff.Initialize( inData->fInOutDataBuff );
if ( siResult != eDSNoErr ) throw( siResult );
siResult = inBuff.GetDataBlockCount( &uiCount );
if ( siResult != eDSNoErr ) throw( siResult );
uiIndex = inData->fInRecEntryIndex;
if ( uiIndex == 0 ) throw( (SInt32)eDSInvalidIndex );
if ( uiIndex > uiCount ) throw( (SInt32)eDSIndexOutOfRange );
pData = inBuff.GetDataBlock( uiIndex, &uberOffset );
if ( pData == NULL ) throw( (SInt32)eDSCorruptBuffer );
buffLen = inBuff.GetDataBlockLength( uiIndex );
pData += 4;
offset = 0;
if (2 + offset > buffLen) throw( (SInt32)eDSInvalidBuffFormat );
::memcpy( &usTypeLen, pData, 2 );
pData += 2;
offset += 2;
pRecType = pData;
pData += usTypeLen;
offset += usTypeLen;
if (2 + offset > buffLen) throw( (SInt32)eDSInvalidBuffFormat );
::memcpy( &usNameLen, pData, 2 );
pData += 2;
offset += 2;
pRecName = pData;
pData += usNameLen;
offset += usNameLen;
if (2 + offset > buffLen) throw( (SInt32)eDSInvalidBuffFormat );
::memcpy( &usAttrCnt, pData, 2 );
pRecEntry = (tRecordEntry *)::calloc( 1, sizeof( tRecordEntry ) + usNameLen + usTypeLen + 4 + kBuffPad );
pRecEntry->fRecordNameAndType.fBufferSize = usNameLen + usTypeLen + 4 + kBuffPad;
pRecEntry->fRecordNameAndType.fBufferLength = usNameLen + usTypeLen + 4;
::memcpy( pRecEntry->fRecordNameAndType.fBufferData, &usNameLen, 2 );
uiOffset += 2;
::memcpy( pRecEntry->fRecordNameAndType.fBufferData + uiOffset, pRecName, usNameLen );
uiOffset += usNameLen;
::memcpy( pRecEntry->fRecordNameAndType.fBufferData + uiOffset, &usTypeLen, 2 );
uiOffset += 2;
::memcpy( pRecEntry->fRecordNameAndType.fBufferData + uiOffset, pRecType, usTypeLen );
pRecEntry->fRecordAttributeCount = usAttrCnt;
pContext = MakeContextData();
if ( pContext == NULL ) throw( (SInt32)eMemoryAllocError );
pContext->offset = uberOffset + offset + 4;
gCacheNodeRef->AddItem( inData->fOutAttrListRef, pContext );
inData->fOutRecEntryPtr = pRecEntry;
}
catch( SInt32 err )
{
siResult = err;
}
return( siResult );
}
SInt32 CCachePlugin::GetAttributeEntry ( sGetAttributeEntry *inData )
{
SInt32 siResult = eDSNoErr;
UInt16 usAttrTypeLen = 0;
UInt16 usAttrCnt = 0;
UInt32 usAttrLen = 0;
UInt16 usValueCnt = 0;
UInt32 usValueLen = 0;
UInt32 i = 0;
UInt32 uiIndex = 0;
UInt32 uiAttrEntrySize = 0;
UInt32 uiOffset = 0;
UInt32 uiTotalValueSize = 0;
UInt32 offset = 0;
UInt32 buffSize = 0;
UInt32 buffLen = 0;
char *p = NULL;
char *pAttrType = NULL;
tDataBuffer *pDataBuff = NULL;
tAttributeValueListRef attrValueListRef = 0;
tAttributeEntryPtr pAttribInfo = NULL;
sCacheContextData *pAttrContext = NULL;
sCacheContextData *pValueContext = NULL;
try
{
if ( inData == NULL ) throw( (SInt32)eMemoryError );
pAttrContext = (sCacheContextData *)gCacheNodeRef->GetItemData( inData->fInAttrListRef );
if ( pAttrContext == NULL ) throw( (SInt32)eDSBadContextData );
uiIndex = inData->fInAttrInfoIndex;
if (uiIndex == 0) throw( (SInt32)eDSInvalidIndex );
pDataBuff = inData->fInOutDataBuff;
if ( pDataBuff == NULL ) throw( (SInt32)eDSNullDataBuff );
buffSize = pDataBuff->fBufferSize;
p = pDataBuff->fBufferData + pAttrContext->offset;
offset = pAttrContext->offset;
if (2 + offset > buffSize) throw( (SInt32)eDSInvalidBuffFormat );
::memcpy( &usAttrCnt, p, 2 );
if (uiIndex > usAttrCnt) throw( (SInt32)eDSIndexOutOfRange );
p += 2;
offset += 2;
for ( i = 1; i < uiIndex; i++ )
{
if (4 + offset > buffSize) throw( (SInt32)eDSInvalidBuffFormat );
::memcpy( &usAttrLen, p, 4 );
p += 4 + usAttrLen;
offset += 4 + usAttrLen;
}
uiOffset = offset;
if (4 + offset > buffSize) throw( (SInt32)eDSInvalidBuffFormat );
::memcpy( &usAttrLen, p, 4 );
p += 4;
offset += 4;
buffLen = offset + usAttrLen;
if (2 + offset > buffLen) throw( (SInt32)eDSInvalidBuffFormat );
::memcpy( &usAttrTypeLen, p, 2 );
pAttrType = p + 2;
p += 2 + usAttrTypeLen;
offset += 2 + usAttrTypeLen;
if (2 + offset > buffLen) throw( (SInt32)eDSInvalidBuffFormat );
::memcpy( &usValueCnt, p, 2 );
p += 2;
offset += 2;
for ( i = 0; i < usValueCnt; i++ )
{
if (4 + offset > buffLen) throw( (SInt32)eDSInvalidBuffFormat );
::memcpy( &usValueLen, p, 4 );
p += 4 + usValueLen;
offset += 4 + usValueLen;
uiTotalValueSize += usValueLen;
}
uiAttrEntrySize = sizeof( tAttributeEntry ) + usAttrTypeLen + kBuffPad;
pAttribInfo = (tAttributeEntry *)::calloc( 1, uiAttrEntrySize );
pAttribInfo->fAttributeValueCount = usValueCnt;
pAttribInfo->fAttributeDataSize = uiTotalValueSize;
pAttribInfo->fAttributeValueMaxSize = 512; pAttribInfo->fAttributeSignature.fBufferSize = usAttrTypeLen + kBuffPad;
pAttribInfo->fAttributeSignature.fBufferLength = usAttrTypeLen;
::memcpy( pAttribInfo->fAttributeSignature.fBufferData, pAttrType, usAttrTypeLen );
attrValueListRef = inData->fOutAttrValueListRef;
pValueContext = MakeContextData();
if ( pValueContext == NULL ) throw( (SInt32)eMemoryAllocError );
pValueContext->offset = uiOffset;
gCacheNodeRef->AddItem( inData->fOutAttrValueListRef, pValueContext );
inData->fOutAttrInfoPtr = pAttribInfo;
}
catch( SInt32 err )
{
siResult = err;
}
return( siResult );
}
SInt32 CCachePlugin::GetAttributeValue ( sGetAttributeValue *inData )
{
SInt32 siResult = eDSNoErr;
UInt16 usValueCnt = 0;
UInt32 usValueLen = 0;
UInt16 usAttrNameLen = 0;
UInt32 i = 0;
UInt32 uiIndex = 0;
UInt32 offset = 0;
char *p = NULL;
tDataBuffer *pDataBuff = NULL;
tAttributeValueEntry *pAttrValue = NULL;
sCacheContextData *pValueContext = NULL;
UInt32 buffSize = 0;
UInt32 buffLen = 0;
UInt32 attrLen = 0;
try
{
pValueContext = (sCacheContextData *)gCacheNodeRef->GetItemData( inData->fInAttrValueListRef );
if ( pValueContext == NULL ) throw( (SInt32)eDSBadContextData );
uiIndex = inData->fInAttrValueIndex;
if (uiIndex == 0) throw( (SInt32)eDSInvalidIndex );
pDataBuff = inData->fInOutDataBuff;
if ( pDataBuff == NULL ) throw( (SInt32)eDSNullDataBuff );
buffSize = pDataBuff->fBufferSize;
p = pDataBuff->fBufferData + pValueContext->offset;
offset = pValueContext->offset;
if (4 + offset > buffSize) throw( (SInt32)eDSInvalidBuffFormat );
::memcpy( &attrLen, p, 4 );
buffLen = attrLen + pValueContext->offset + 4;
if (buffLen > buffSize) throw( (SInt32)eDSInvalidBuffFormat );
p += 4;
offset += 4;
if (2 + offset > buffLen) throw( (SInt32)eDSInvalidBuffFormat );
::memcpy( &usAttrNameLen, p, 2 );
p += 2 + usAttrNameLen;
offset += 2 + usAttrNameLen;
if (2 + offset > buffLen) throw( (SInt32)eDSInvalidBuffFormat );
::memcpy( &usValueCnt, p, 2 );
p += 2;
offset += 2;
if (uiIndex > usValueCnt) throw( (SInt32)eDSIndexOutOfRange );
for ( i = 1; i < uiIndex; i++ )
{
if (4 + offset > buffLen) throw( (SInt32)eDSInvalidBuffFormat );
::memcpy( &usValueLen, p, 4 );
p += 4 + usValueLen;
offset += 4 + usValueLen;
}
if (4 + offset > buffLen) throw( (SInt32)eDSInvalidBuffFormat );
::memcpy( &usValueLen, p, 4 );
p += 4;
offset += 4;
pAttrValue = (tAttributeValueEntry *)::calloc( 1, sizeof( tAttributeValueEntry ) + usValueLen + kBuffPad );
pAttrValue->fAttributeValueData.fBufferSize = usValueLen + kBuffPad;
pAttrValue->fAttributeValueData.fBufferLength = usValueLen;
if ( usValueLen + offset > buffLen ) throw( (SInt32)eDSInvalidBuffFormat );
::memcpy( pAttrValue->fAttributeValueData.fBufferData, p, usValueLen );
pAttrValue->fAttributeValueID = 0x00;
inData->fOutAttrValue = pAttrValue;
}
catch( SInt32 err )
{
siResult = err;
}
return( siResult );
}
SInt32 CCachePlugin::CloseAttributeList ( sCloseAttributeList *inData )
{
SInt32 siResult = eDSNoErr;
sCacheContextData *pContext = NULL;
pContext = (sCacheContextData *)gCacheNodeRef->GetItemData( inData->fInAttributeListRef );
if ( pContext != NULL )
{
gCacheNodeRef->RemoveItem( inData->fInAttributeListRef );
}
else
{
siResult = eDSInvalidAttrListRef;
}
return( siResult );
}
SInt32 CCachePlugin::CloseAttributeValueList ( sCloseAttributeValueList *inData )
{
SInt32 siResult = eDSNoErr;
sCacheContextData *pContext = NULL;
pContext = (sCacheContextData *)gCacheNodeRef->GetItemData( inData->fInAttributeValueListRef );
if ( pContext != NULL )
{
gCacheNodeRef->RemoveItem( inData->fInAttributeValueListRef );
}
else
{
siResult = eDSInvalidAttrValueRef;
}
return( siResult );
}
SInt32 CCachePlugin::ReleaseContinueData ( sReleaseContinueData *inData )
{
SInt32 siResult = eDSNoErr;
sCacheContinueData *pContinue = NULL;
pContinue = (sCacheContinueData *) gCacheNodeContinue->GetPointer( inData->fInContinueData );
if ( pContinue != NULL )
{
siResult = dsReleaseContinueData( pContinue->fNodeRef, pContinue->fContinue );
}
if ( gCacheNodeContinue->RemoveContext( inData->fInContinueData ) != eDSNoErr )
{
siResult = eDSInvalidContext;
}
return( siResult );
}
SInt32 CCachePlugin::DoPlugInCustomCall ( sDoPlugInCustomCall *inData )
{
SInt32 siResult = eDSNoErr;
sCacheContextData *pContext = NULL;
AuthorizationRef authRef = 0;
AuthorizationExternalForm blankExtForm;
bool verifyAuthRef = true;
char *buffer = inData->fInRequestData->fBufferData;
UInt32 bufferLen = inData->fInRequestData->fBufferLength;
pContext = (sCacheContextData *) gCacheNodeRef->GetItemData( inData->fInNodeRef );
if ( pContext == NULL ) {
siResult = eDSInvalidNodeRef;
goto done;
}
if ( bufferLen < sizeof(AuthorizationExternalForm) ) {
siResult = eDSInvalidBuffFormat;
goto done;
}
if ( pContext->fEffectiveUID == 0 ) {
bzero( &blankExtForm, sizeof(AuthorizationExternalForm) );
if ( memcmp(inData->fInRequestData->fBufferData, &blankExtForm, sizeof(AuthorizationExternalForm)) == 0 ) {
verifyAuthRef = false;
}
}
if ( verifyAuthRef ) {
int status = AuthorizationCreateFromExternalForm( (AuthorizationExternalForm *)inData->fInRequestData->fBufferData, &authRef );
if ( status != errAuthorizationSuccess ) {
DbgLog( kLogPlugin, "CCachePlugin: AuthorizationCreateFromExternalForm returned error %d", status );
siResult = eDSPermissionError;
goto done;
}
AuthorizationItem rights[] = { {"system.services.directory.configure", 0, 0, 0} };
AuthorizationItemSet rightSet = { sizeof(rights)/ sizeof(*rights), rights };
status = AuthorizationCopyRights( authRef, &rightSet, NULL, kAuthorizationFlagExtendRights, NULL );
if ( status != errAuthorizationSuccess ) {
DbgLog( kLogPlugin, "CCachePlugin: AuthorizationCopyRights returned error %d", siResult );
siResult = eDSPermissionError;
goto done;
}
}
if ( inData->fInRequestCode == eDSCustomCallCacheRegisterLocalSearchPID || inData->fInRequestCode == eDSCustomCallCacheUnregisterLocalSearchPID ) {
if ( bufferLen < sizeof(AuthorizationExternalForm) + sizeof(pid_t) ) {
siResult = eDSInvalidBuffFormat;
goto done;
}
pid_t thePID = *((pid_t *) (buffer + sizeof(AuthorizationExternalForm)));
if ( thePID > 0 ) {
fPIDListLock.WaitLock();
if ( inData->fInRequestCode == eDSCustomCallCacheRegisterLocalSearchPID ) {
fLocalOnlyPIDs.insert( thePID );
dispatch_source_proc_create( thePID,
DISPATCH_PROC_EXIT | DISPATCH_PROC_EXEC,
NULL,
dispatch_get_concurrent_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT),
^(dispatch_source_t ds) {
fPIDListLock.WaitLock();
DbgLog( kLogInfo, "CCachePlugin - deregistered PID %d from exception list", thePID );
fLocalOnlyPIDs.erase( thePID );
fPIDListLock.SignalLock();
} );
}
else {
fLocalOnlyPIDs.erase( thePID );
}
fPIDListLock.SignalLock();
}
}
done:
return( siResult );
}
#pragma mark -
#pragma mark Libinfo result parsing routines
#pragma mark -
sCacheValidation* ParsePasswdEntry( tDirReference inDirRef, tDirNodeReference inNodeRef, kvbuf_t *inBuffer, tDataBufferPtr inDataBuffer,
tRecordEntryPtr inRecEntry, tAttributeListRef inAttrListRef, void *additionalInfo, CCache *inCache, const char **inKeys )
{
tAttributeValueListRef valueRef = 0;
tAttributeEntry *pAttrEntry = nil;
tAttributeValueEntry *pValueEntry = nil;
tDirStatus siResult;
kvbuf_t *tempBuffer = kvbuf_new_zone( malloc_default_purgeable_zone() );
sCacheValidation *valid_t = NULL;
bool serviceAccount = false;
uint32_t entryFlags = CACHE_ENTRY_TYPE_USER;
if ( additionalInfo != NULL ) {
entryFlags |= *((uint32_t *) additionalInfo);
}
kvbuf_add_dict( tempBuffer );
for (unsigned int i = 1; i <= inRecEntry->fRecordAttributeCount; i++)
{
siResult = ::dsGetAttributeEntry( inNodeRef, inDataBuffer, inAttrListRef, i, &valueRef, &pAttrEntry );
if ( ( siResult == eDSNoErr ) && ( pAttrEntry->fAttributeValueCount > 0 ) )
{
siResult = ::dsGetAttributeValue( inNodeRef, inDataBuffer, 1, valueRef, &pValueEntry );
if ( ::strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrMetaNodeLocation ) == 0 )
{
if ( valid_t == NULL )
valid_t = new sCacheValidation( pValueEntry->fAttributeValueData.fBufferData );
if ( (entryFlags & CACHE_ENTRY_TYPE_EXTENDED) != 0 ) {
kvbuf_add_key( tempBuffer, kDSNAttrMetaNodeLocation );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
}
else if ( ::strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrRecordName ) == 0 )
{
kvbuf_add_key( tempBuffer, "pw_name" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
for ( UInt32 idx=2; idx <= pAttrEntry->fAttributeValueCount; idx++ )
{
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
siResult = dsGetAttributeValue( inNodeRef, inDataBuffer, idx, valueRef, &pValueEntry );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
}
else if ( ::strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDS1AttrPassword ) == 0 )
{
kvbuf_add_key( tempBuffer, "pw_passwd" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
else if ( ::strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDS1AttrUniqueID ) == 0 )
{
kvbuf_add_key( tempBuffer, "pw_uid" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
else if ( ::strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDS1AttrPrimaryGroupID ) == 0 )
{
kvbuf_add_key( tempBuffer, "pw_gid" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
else if ( ::strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDS1AttrNFSHomeDirectory ) == 0 )
{
kvbuf_add_key( tempBuffer, "pw_dir" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
else if ( ::strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDS1AttrUserShell ) == 0 )
{
kvbuf_add_key( tempBuffer, "pw_shell" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
else if ( ::strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDS1AttrGeneratedUID ) == 0 )
{
kvbuf_add_key( tempBuffer, "pw_uuid" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
else if ( ::strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDS1AttrDistinguishedName ) == 0 )
{
kvbuf_add_key( tempBuffer, "pw_gecos" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
else if ( ::strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrKeywords ) == 0 )
{
UInt32 index = 1;
do {
if ( ::strcmp( pValueEntry->fAttributeValueData.fBufferData, "com.apple.ServiceAccount" ) == 0 )
{
serviceAccount = true;
break;
}
if ( ++index <= pAttrEntry->fAttributeValueCount )
{
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
siResult = dsGetAttributeValue( inNodeRef, inDataBuffer, index, valueRef, &pValueEntry );
continue;
}
break;
} while (1);
}
else if ( (entryFlags & CACHE_ENTRY_TYPE_EXTENDED) != 0 )
{
kvbuf_add_key( tempBuffer, pAttrEntry->fAttributeSignature.fBufferData );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
for ( UInt32 idx = 2; idx <= pAttrEntry->fAttributeValueCount; idx++ )
{
if ( pValueEntry != NULL ) {
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
siResult = dsGetAttributeValue( inNodeRef, inDataBuffer, idx, valueRef, &pValueEntry );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
if ( pValueEntry != NULL ) {
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
}
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
}
if ( valueRef != 0 )
{
dsCloseAttributeValueList( valueRef );
valueRef = 0;
}
if ( pAttrEntry != NULL )
{
dsDeallocAttributeEntry( inDirRef, pAttrEntry );
pAttrEntry = NULL;
}
}
if (!serviceAccount)
kvbuf_append_kvbuf( inBuffer, tempBuffer );
if( inCache != NULL && inKeys != NULL && !serviceAccount )
CCachePlugin::AddEntryToCacheWithKeys( inCache, valid_t, tempBuffer, entryFlags, kCacheTime, inKeys );
else
kvbuf_free( tempBuffer );
return( valid_t );
}
sCacheValidation* ParseGroupEntry( tDirReference inDirRef, tDirNodeReference inNodeRef, kvbuf_t *inBuffer, tDataBufferPtr inDataBuffer,
tRecordEntryPtr inRecEntry, tAttributeListRef inAttrListRef, void *additionalInfo, CCache *inCache, const char **inKeys )
{
tAttributeValueListRef valueRef = 0;
tAttributeEntry *pAttrEntry = nil;
tAttributeValueEntry *pValueEntry = nil;
tDirStatus siResult;
kvbuf_t *tempBuffer = kvbuf_new_zone( malloc_default_purgeable_zone() );
sCacheValidation *valid_t = NULL;
uint32_t entryFlags = CACHE_ENTRY_TYPE_GROUP;
if ( additionalInfo != NULL ) {
entryFlags |= *((uint32_t *) additionalInfo);
}
kvbuf_add_dict( tempBuffer );
for (unsigned int i = 1; i <= inRecEntry->fRecordAttributeCount; i++)
{
siResult = dsGetAttributeEntry( inNodeRef, inDataBuffer, inAttrListRef, i, &valueRef, &pAttrEntry );
if ( ( siResult == eDSNoErr ) && ( pAttrEntry->fAttributeValueCount > 0 ) )
{
siResult = ::dsGetAttributeValue( inNodeRef, inDataBuffer, 1, valueRef, &pValueEntry );
if ( ::strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrMetaNodeLocation ) == 0 )
{
if ( valid_t == NULL )
valid_t = new sCacheValidation( pValueEntry->fAttributeValueData.fBufferData );
}
else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrRecordName ) == 0 )
{
kvbuf_add_key( tempBuffer, "gr_name" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
for ( UInt32 idx=2; idx <= pAttrEntry->fAttributeValueCount; idx++ )
{
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
siResult = dsGetAttributeValue( inNodeRef, inDataBuffer, idx, valueRef, &pValueEntry );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
}
else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDS1AttrPassword ) == 0 )
{
kvbuf_add_key( tempBuffer, "gr_passwd" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDS1AttrPrimaryGroupID ) == 0 )
{
kvbuf_add_key( tempBuffer, "gr_gid" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrGroupMembership ) == 0 )
{
kvbuf_add_key( tempBuffer, "gr_mem" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
for (UInt32 idx=2; idx <= pAttrEntry->fAttributeValueCount; idx++)
{
if ( pValueEntry != NULL ) {
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
siResult = dsGetAttributeValue( inNodeRef, inDataBuffer, idx, valueRef, &pValueEntry );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
}
else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDS1AttrGeneratedUID ) == 0 )
{
kvbuf_add_key( tempBuffer, "gr_uuid" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
else if ( (entryFlags & CACHE_ENTRY_TYPE_EXTENDED) != 0 )
{
kvbuf_add_key( tempBuffer, pAttrEntry->fAttributeSignature.fBufferData );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
for ( UInt32 idx = 2; idx <= pAttrEntry->fAttributeValueCount; idx++ )
{
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
siResult = dsGetAttributeValue( inNodeRef, inDataBuffer, idx, valueRef, &pValueEntry );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
}
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
}
if ( valueRef != 0 )
{
dsCloseAttributeValueList( valueRef );
valueRef = 0;
}
if ( pAttrEntry != NULL )
{
dsDeallocAttributeEntry( inDirRef, pAttrEntry );
pAttrEntry = NULL;
}
}
kvbuf_append_kvbuf( inBuffer, tempBuffer );
if( inCache != NULL && inKeys != NULL )
CCachePlugin::AddEntryToCacheWithKeys( inCache, valid_t, tempBuffer, entryFlags, kCacheTime, inKeys );
else
kvbuf_free( tempBuffer );
return( valid_t );
}
sCacheValidation* ParseMountEntry( tDirReference inDirRef, tDirNodeReference inNodeRef, kvbuf_t *inBuffer, tDataBufferPtr inDataBuffer,
tRecordEntryPtr inRecEntry, tAttributeListRef inAttrListRef, void *additionalInfo, CCache *inCache, const char **inKeys )
{
tAttributeValueListRef valueRef = 0;
tAttributeEntry *pAttrEntry = nil;
tAttributeValueEntry *pValueEntry = nil;
tDirStatus siResult;
Boolean bFreqAdded = false;
Boolean bPassAdded = false;
kvbuf_t *tempBuffer = kvbuf_new_zone( malloc_default_purgeable_zone() );
sCacheValidation *valid_t = NULL;
kvbuf_add_dict( tempBuffer );
for (unsigned int i = 1; i <= inRecEntry->fRecordAttributeCount; i++)
{
siResult = dsGetAttributeEntry( inNodeRef, inDataBuffer, inAttrListRef, i, &valueRef, &pAttrEntry );
if ( ( siResult == eDSNoErr ) && ( pAttrEntry->fAttributeValueCount > 0 ) )
{
siResult = ::dsGetAttributeValue( inNodeRef, inDataBuffer, 1, valueRef, &pValueEntry );
if ( ::strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrMetaNodeLocation ) == 0 )
{
if ( valid_t == NULL )
valid_t = new sCacheValidation( pValueEntry->fAttributeValueData.fBufferData );
}
else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrRecordName ) == 0 )
{
kvbuf_add_key( tempBuffer, "fs_spec" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDS1AttrVFSLinkDir ) == 0 )
{
kvbuf_add_key( tempBuffer, "fs_file" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDS1AttrVFSType ) == 0 )
{
kvbuf_add_key( tempBuffer, "fs_vfstype" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrVFSOpts ) == 0 )
{
char tempBuff[256] = { 0, };
const char *fs_type = "rw";
kvbuf_add_key( tempBuffer, "fs_mntops" );
if( strcmp(pValueEntry->fAttributeValueData.fBufferData, "ro") == 0 )
fs_type = "ro";
else if( strcmp(pValueEntry->fAttributeValueData.fBufferData, "sw") == 0 )
fs_type = "sw";
else if( strcmp(pValueEntry->fAttributeValueData.fBufferData, "xx") == 0 )
fs_type = "xx";
strlcpy( tempBuff, pValueEntry->fAttributeValueData.fBufferData, sizeof(tempBuff) );
for (UInt32 idx=2; idx <= pAttrEntry->fAttributeValueCount; idx++)
{
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
dsGetAttributeValue( inNodeRef, inDataBuffer, idx, valueRef, &pValueEntry );
if( strcmp(pValueEntry->fAttributeValueData.fBufferData, "ro") == 0 )
fs_type = "ro";
else if( strcmp(pValueEntry->fAttributeValueData.fBufferData, "sw") == 0 )
fs_type = "sw";
else if( strcmp(pValueEntry->fAttributeValueData.fBufferData, "xx") == 0 )
fs_type = "xx";
strlcat( tempBuff, ",", sizeof(tempBuff) );
strlcat( tempBuff, pValueEntry->fAttributeValueData.fBufferData, sizeof(tempBuff) );
}
kvbuf_add_val( tempBuffer, tempBuff );
kvbuf_add_key( tempBuffer, "fs_type" );
kvbuf_add_val( tempBuffer, fs_type );
}
else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDS1AttrVFSDumpFreq ) == 0 )
{
bFreqAdded = true;
kvbuf_add_key( tempBuffer, "fs_freq" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDS1AttrVFSPassNo ) == 0 )
{
bPassAdded = true;
kvbuf_add_key( tempBuffer, "fs_passno" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
}
if ( valueRef != 0 )
{
dsCloseAttributeValueList( valueRef );
valueRef = 0;
}
if ( pAttrEntry != NULL )
{
dsDeallocAttributeEntry( inDirRef, pAttrEntry );
pAttrEntry = NULL;
}
}
if( bFreqAdded == false )
{
kvbuf_add_key( tempBuffer, "fs_freq" );
kvbuf_add_val( tempBuffer, "0" );
}
if( bPassAdded == false )
{
kvbuf_add_key( tempBuffer, "fs_passno" );
kvbuf_add_val( tempBuffer, "0" );
}
kvbuf_append_kvbuf( inBuffer, tempBuffer );
if( inCache != NULL && inKeys != NULL )
CCachePlugin::AddEntryToCacheWithKeys( inCache, valid_t, tempBuffer, CACHE_ENTRY_TYPE_MOUNT, kCacheTime, inKeys );
else
kvbuf_free( tempBuffer );
return( valid_t );
}
sCacheValidation* ParseAliasEntry( tDirReference inDirRef, tDirNodeReference inNodeRef, kvbuf_t *inBuffer, tDataBufferPtr inDataBuffer,
tRecordEntryPtr inRecEntry, tAttributeListRef inAttrListRef, void *additionalInfo, CCache *inCache, const char **inKeys )
{
tAttributeValueListRef valueRef = 0;
tAttributeEntry *pAttrEntry = nil;
tAttributeValueEntry *pValueEntry = nil;
tDirStatus siResult;
kvbuf_t *tempBuffer = kvbuf_new_zone( malloc_default_purgeable_zone() );
sCacheValidation *valid_t = NULL;
kvbuf_add_dict( tempBuffer );
for (unsigned int i = 1; i <= inRecEntry->fRecordAttributeCount; i++)
{
siResult = dsGetAttributeEntry( inNodeRef, inDataBuffer, inAttrListRef, i, &valueRef, &pAttrEntry );
if ( ( siResult == eDSNoErr ) && ( pAttrEntry->fAttributeValueCount > 0 ) )
{
siResult = ::dsGetAttributeValue( inNodeRef, inDataBuffer, 1, valueRef, &pValueEntry );
if ( ::strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrMetaNodeLocation ) == 0 )
{
if ( valid_t == NULL )
valid_t = new sCacheValidation( pValueEntry->fAttributeValueData.fBufferData );
}
else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrRecordName ) == 0 )
{
kvbuf_add_key( tempBuffer, "alias_name" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrMember ) == 0 ||
strcmp( pAttrEntry->fAttributeSignature.fBufferData, "dsAttrTypeNative:members" ) == 0 )
{
kvbuf_add_key( tempBuffer, "alias_members" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
for (UInt32 idx=2; idx <= pAttrEntry->fAttributeValueCount; idx++)
{
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
dsGetAttributeValue( inNodeRef, inDataBuffer, idx, valueRef, &pValueEntry );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
}
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
}
if ( valueRef != 0 )
{
dsCloseAttributeValueList( valueRef );
valueRef = 0;
}
if ( pAttrEntry != NULL )
{
dsDeallocAttributeEntry( inDirRef, pAttrEntry );
pAttrEntry = NULL;
}
}
kvbuf_append_kvbuf( inBuffer, tempBuffer );
if( inCache != NULL && inKeys != NULL )
CCachePlugin::AddEntryToCacheWithKeys( inCache, valid_t, tempBuffer, CACHE_ENTRY_TYPE_ALIAS, kCacheTime, inKeys );
else
kvbuf_free( tempBuffer );
return( valid_t );
}
sCacheValidation* ParseServiceEntry( tDirReference inDirRef, tDirNodeReference inNodeRef, kvbuf_t *inBuffer, tDataBufferPtr inDataBuffer,
tRecordEntryPtr inRecEntry, tAttributeListRef inAttrListRef, void *additionalInfo, CCache *inCache, const char **inKeys )
{
tAttributeValueListRef valueRef = 0;
tAttributeEntry *pAttrEntry = nil;
tAttributeValueEntry *pValueEntry = nil;
tDirStatus siResult;
kvbuf_t *tempBuffer = kvbuf_new_zone( malloc_default_purgeable_zone() );
Boolean bFoundProtocol = false;
char *portAndProtocols[64];
uint32_t iProtocolCount = 0;
char *pProtocol = NULL;
char *pPort = NULL;
sCacheValidation *valid_t = NULL;
if( additionalInfo != NULL )
{
pPort = ((char **) additionalInfo)[0];
pProtocol = ((char **) additionalInfo)[1];
}
kvbuf_add_dict( tempBuffer );
for (unsigned int i = 1; i <= inRecEntry->fRecordAttributeCount; i++)
{
siResult = dsGetAttributeEntry( inNodeRef, inDataBuffer, inAttrListRef, i, &valueRef, &pAttrEntry );
if ( ( siResult == eDSNoErr ) && ( pAttrEntry->fAttributeValueCount > 0 ) )
{
siResult = ::dsGetAttributeValue( inNodeRef, inDataBuffer, 1, valueRef, &pValueEntry );
if ( ::strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrMetaNodeLocation ) == 0 )
{
if ( valid_t == NULL )
valid_t = new sCacheValidation( pValueEntry->fAttributeValueData.fBufferData );
}
else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrRecordName ) == 0 )
{
kvbuf_add_key( tempBuffer, "s_name" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
if( pAttrEntry->fAttributeValueCount > 1 )
kvbuf_add_key( tempBuffer, "s_aliases" );
for (UInt32 idx=2; idx <= pAttrEntry->fAttributeValueCount; idx++)
{
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
dsGetAttributeValue( inNodeRef, inDataBuffer, idx, valueRef, &pValueEntry );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
}
else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, "dsAttrTypeNative:PortAndProtocol" ) == 0 )
{
UInt32 idx = 1;
do
{
if( pProtocol != NULL )
{
if( ((char *)pProtocol)[0] == '\0' )
{
portAndProtocols[iProtocolCount] = strdup( pValueEntry->fAttributeValueData.fBufferData );
iProtocolCount++;
break;
}
else
{
char *slash = strchr( pValueEntry->fAttributeValueData.fBufferData, '/' );
if( slash != NULL )
{
if( strcmp(slash+1, (char *)pProtocol) == 0 )
{
*slash = '\0';
kvbuf_add_key( tempBuffer, "s_port" );
kvbuf_add_val( tempBuffer, (pPort != NULL ? pPort : pValueEntry->fAttributeValueData.fBufferData) );
bFoundProtocol = true;
}
}
}
}
else
{
portAndProtocols[iProtocolCount] = strdup( pValueEntry->fAttributeValueData.fBufferData );
iProtocolCount++;
}
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
if( (++idx) <= pAttrEntry->fAttributeValueCount )
{
dsGetAttributeValue( inNodeRef, inDataBuffer, idx, valueRef, &pValueEntry );
}
} while( idx <= pAttrEntry->fAttributeValueCount && bFoundProtocol == false );
}
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
}
if ( valueRef != 0 )
{
dsCloseAttributeValueList( valueRef );
valueRef = 0;
}
if ( pAttrEntry != NULL )
{
dsDeallocAttributeEntry( inDirRef, pAttrEntry );
pAttrEntry = NULL;
}
}
if( bFoundProtocol == true )
{
kvbuf_add_key( tempBuffer, "s_proto" );
kvbuf_add_val( tempBuffer, (char *) pProtocol );
kvbuf_append_kvbuf( inBuffer, tempBuffer );
}
else if( iProtocolCount > 0 )
{
for( uint32_t ii = 0; ii < iProtocolCount; ii++ )
{
kvbuf_t *tempBuffer2 = kvbuf_init( tempBuffer->databuf, tempBuffer->datalen );
kvbuf_reset( tempBuffer2 );
kvbuf_next_dict( tempBuffer2 );
char *slash = strchr( portAndProtocols[ii], '/' );
if( slash != NULL )
{
*slash = '\0';
kvbuf_add_key( tempBuffer2, "s_port" );
kvbuf_add_val( tempBuffer2, portAndProtocols[ii] );
kvbuf_add_key( tempBuffer2, "s_proto" );
kvbuf_add_val( tempBuffer2, slash+1 );
kvbuf_append_kvbuf( inBuffer, tempBuffer2 );
DSFree( portAndProtocols[ii] );
}
kvbuf_free( tempBuffer2 );
}
}
kvbuf_free( tempBuffer );
return( valid_t );
}
sCacheValidation* ParseProtocolEntry( tDirReference inDirRef, tDirNodeReference inNodeRef, kvbuf_t *inBuffer, tDataBufferPtr inDataBuffer,
tRecordEntryPtr inRecEntry, tAttributeListRef inAttrListRef, void *additionalInfo, CCache *inCache, const char **inKeys )
{
tAttributeValueListRef valueRef = 0;
tAttributeEntry *pAttrEntry = nil;
tAttributeValueEntry *pValueEntry = nil;
tDirStatus siResult;
kvbuf_t *tempBuffer = kvbuf_new_zone( malloc_default_purgeable_zone() );
sCacheValidation *valid_t = NULL;
kvbuf_add_dict( tempBuffer );
for (unsigned int i = 1; i <= inRecEntry->fRecordAttributeCount; i++)
{
siResult = dsGetAttributeEntry( inNodeRef, inDataBuffer, inAttrListRef, i, &valueRef, &pAttrEntry );
if ( ( siResult == eDSNoErr ) && ( pAttrEntry->fAttributeValueCount > 0 ) )
{
siResult = ::dsGetAttributeValue( inNodeRef, inDataBuffer, 1, valueRef, &pValueEntry );
if ( ::strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrMetaNodeLocation ) == 0 )
{
if ( valid_t == NULL )
valid_t = new sCacheValidation( pValueEntry->fAttributeValueData.fBufferData );
}
else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrRecordName ) == 0 )
{
kvbuf_add_key( tempBuffer, "p_name" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
if( pAttrEntry->fAttributeValueCount > 1 )
kvbuf_add_key( tempBuffer, "p_aliases" );
for (UInt32 idx=2; idx <= pAttrEntry->fAttributeValueCount; idx++)
{
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
dsGetAttributeValue( inNodeRef, inDataBuffer, idx, valueRef, &pValueEntry );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
}
else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, "dsAttrTypeNative:number" ) == 0 )
{
kvbuf_add_key( tempBuffer, "p_proto" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
}
if ( valueRef != 0 )
{
dsCloseAttributeValueList( valueRef );
valueRef = 0;
}
if ( pAttrEntry != NULL )
{
dsDeallocAttributeEntry( inDirRef, pAttrEntry );
pAttrEntry = NULL;
}
}
kvbuf_append_kvbuf( inBuffer, tempBuffer );
if( inCache != NULL && inKeys != NULL )
CCachePlugin::AddEntryToCacheWithKeys( inCache, valid_t, tempBuffer, CACHE_ENTRY_TYPE_PROTOCOL, kCacheTime, inKeys );
else
kvbuf_free( tempBuffer );
return( valid_t );
}
sCacheValidation* ParseRPCEntry( tDirReference inDirRef, tDirNodeReference inNodeRef, kvbuf_t *inBuffer, tDataBufferPtr inDataBuffer,
tRecordEntryPtr inRecEntry, tAttributeListRef inAttrListRef, void *additionalInfo, CCache *inCache, const char **inKeys )
{
tAttributeValueListRef valueRef = 0;
tAttributeEntry *pAttrEntry = nil;
tAttributeValueEntry *pValueEntry = nil;
tDirStatus siResult;
kvbuf_t *tempBuffer = kvbuf_new_zone( malloc_default_purgeable_zone() );
sCacheValidation *valid_t = NULL;
kvbuf_add_dict( tempBuffer );
for (unsigned int i = 1; i <= inRecEntry->fRecordAttributeCount; i++)
{
siResult = dsGetAttributeEntry( inNodeRef, inDataBuffer, inAttrListRef, i, &valueRef, &pAttrEntry );
if ( ( siResult == eDSNoErr ) && ( pAttrEntry->fAttributeValueCount > 0 ) )
{
siResult = ::dsGetAttributeValue( inNodeRef, inDataBuffer, 1, valueRef, &pValueEntry );
if ( ::strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrMetaNodeLocation ) == 0 )
{
if ( valid_t == NULL )
valid_t = new sCacheValidation( pValueEntry->fAttributeValueData.fBufferData );
}
else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrRecordName ) == 0 )
{
kvbuf_add_key( tempBuffer, "r_name" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
if( pAttrEntry->fAttributeValueCount > 1 )
kvbuf_add_key( tempBuffer, "r_aliases" );
for (UInt32 idx=2; idx <= pAttrEntry->fAttributeValueCount; idx++)
{
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
dsGetAttributeValue( inNodeRef, inDataBuffer, idx, valueRef, &pValueEntry );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
}
else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, "dsAttrTypeNative:number" ) == 0 )
{
kvbuf_add_key( tempBuffer, "r_number" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
}
if ( valueRef != 0 )
{
dsCloseAttributeValueList( valueRef );
valueRef = 0;
}
if ( pAttrEntry != NULL )
{
dsDeallocAttributeEntry( inDirRef, pAttrEntry );
pAttrEntry = NULL;
}
}
kvbuf_append_kvbuf( inBuffer, tempBuffer );
if( inCache != NULL && inKeys != NULL )
CCachePlugin::AddEntryToCacheWithKeys( inCache, valid_t, tempBuffer, CACHE_ENTRY_TYPE_RPC, kCacheTime, inKeys );
else
kvbuf_free( tempBuffer );
return( valid_t );
}
sCacheValidation* ParseNetworkEntry( tDirReference inDirRef, tDirNodeReference inNodeRef, kvbuf_t *inBuffer, tDataBufferPtr inDataBuffer,
tRecordEntryPtr inRecEntry, tAttributeListRef inAttrListRef, void *additionalInfo, CCache *inCache, const char **inKeys )
{
tAttributeValueListRef valueRef = 0;
tAttributeEntry *pAttrEntry = nil;
tAttributeValueEntry *pValueEntry = nil;
tDirStatus siResult;
kvbuf_t *tempBuffer = kvbuf_new_zone( malloc_default_purgeable_zone() );
sCacheValidation *valid_t = NULL;
kvbuf_add_dict( tempBuffer );
for (unsigned int i = 1; i <= inRecEntry->fRecordAttributeCount; i++)
{
siResult = dsGetAttributeEntry( inNodeRef, inDataBuffer, inAttrListRef, i, &valueRef, &pAttrEntry );
if ( ( siResult == eDSNoErr ) && ( pAttrEntry->fAttributeValueCount > 0 ) )
{
siResult = ::dsGetAttributeValue( inNodeRef, inDataBuffer, 1, valueRef, &pValueEntry );
if ( ::strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrMetaNodeLocation ) == 0 )
{
if ( valid_t == NULL )
valid_t = new sCacheValidation( pValueEntry->fAttributeValueData.fBufferData );
}
else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrRecordName ) == 0 )
{
kvbuf_add_key( tempBuffer, "n_name" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
if( pAttrEntry->fAttributeValueCount > 1 )
kvbuf_add_key( tempBuffer, "n_aliases" );
for (UInt32 idx=2; idx <= pAttrEntry->fAttributeValueCount; idx++)
{
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
dsGetAttributeValue( inNodeRef, inDataBuffer, idx, valueRef, &pValueEntry );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
}
else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, "dsAttrTypeNative:address" ) == 0 )
{
kvbuf_add_key( tempBuffer, "n_net" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
}
if ( valueRef != 0 )
{
dsCloseAttributeValueList( valueRef );
valueRef = 0;
}
if ( pAttrEntry != NULL )
{
dsDeallocAttributeEntry( inDirRef, pAttrEntry );
pAttrEntry = NULL;
}
}
kvbuf_append_kvbuf( inBuffer, tempBuffer );
if( inCache != NULL && inKeys != NULL )
CCachePlugin::AddEntryToCacheWithKeys( inCache, valid_t, tempBuffer, CACHE_ENTRY_TYPE_NETWORK, kCacheTime, inKeys );
else
kvbuf_free( tempBuffer );
return( valid_t );
}
sCacheValidation* ParseNetGroupEntry( tDirReference inDirRef, tDirNodeReference inNodeRef, kvbuf_t *inBuffer, tDataBufferPtr inDataBuffer,
tRecordEntryPtr inRecEntry, tAttributeListRef inAttrListRef, void *additionalInfo, CCache *inCache,
const char **inKeys )
{
tAttributeValueListRef valueRef = 0;
tAttributeEntry *pAttrEntry = nil;
tAttributeValueEntry *pValueEntry = nil;
tDirStatus siResult;
kvbuf_t *tempBuffer = kvbuf_new_zone( malloc_default_purgeable_zone() );
char **pSearch = (char **) additionalInfo;
char name[256] = { 0, };
sCacheValidation *valid_t = NULL;
for (unsigned int i = 1; i <= inRecEntry->fRecordAttributeCount; i++)
{
siResult = dsGetAttributeEntry( inNodeRef, inDataBuffer, inAttrListRef, i, &valueRef, &pAttrEntry );
if ( ( siResult == eDSNoErr ) && ( pAttrEntry->fAttributeValueCount > 0 ) )
{
siResult = ::dsGetAttributeValue( inNodeRef, inDataBuffer, 1, valueRef, &pValueEntry );
if ( ::strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrMetaNodeLocation ) == 0 )
{
if ( valid_t == NULL )
valid_t = new sCacheValidation( pValueEntry->fAttributeValueData.fBufferData );
}
else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrRecordName ) == 0 )
{
strlcpy( name, pValueEntry->fAttributeValueData.fBufferData, sizeof(name) );
}
else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrNetGroups ) == 0 )
{
UInt32 idx = 1;
do
{
kvbuf_t *nestedGroup = kvbuf_new();
kvbuf_add_dict( nestedGroup );
kvbuf_add_key( nestedGroup, "netgroup" );
kvbuf_add_val( nestedGroup, pValueEntry->fAttributeValueData.fBufferData );
DbgLog( kLogDebug, "CCachePlugin::ParseNetGroupEntry nested group lookup - %s", pValueEntry->fAttributeValueData.fBufferData );
kvbuf_t *nestedData = gCacheNode->DSgetnetgrent( nestedGroup );
kvbuf_append_kvbuf( tempBuffer, nestedData );
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
if( (++idx) <= pAttrEntry->fAttributeValueCount )
{
dsGetAttributeValue( inNodeRef, inDataBuffer, idx, valueRef, &pValueEntry );
}
kvbuf_free( nestedGroup );
kvbuf_free( nestedData );
} while( idx <= pAttrEntry->fAttributeValueCount );
DbgLog( kLogDebug, "CCachePlugin::ParseNetGroupEntry nested group lookup complete" );
}
else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, "dsAttrTypeNative:triplet" ) == 0 )
{
UInt32 idx = 1;
do
{
char *current = pValueEntry->fAttributeValueData.fBufferData;
char *host = strsep( ¤t, "," );
char *user = strsep( ¤t, "," );
char *domain = strsep( ¤t, "," );
if( host != NULL || user != NULL || domain != NULL )
{
if( pSearch != NULL )
{
if( pSearch[0][0] != '\0' && host != NULL && strcmp(pSearch[0], host) != 0 )
{
goto nextValue;
}
if( pSearch[1][0] != '\0' && user != NULL && strcmp(pSearch[1], user) != 0 )
{
goto nextValue;
}
if( pSearch[2][0] != '\0' && domain != NULL && strcmp(pSearch[2], domain) != 0 )
{
goto nextValue;
}
}
kvbuf_add_dict( tempBuffer );
if( host != NULL )
{
kvbuf_add_key( tempBuffer, "host" );
kvbuf_add_val( tempBuffer, host );
}
if( user != NULL )
{
kvbuf_add_key( tempBuffer, "user" );
kvbuf_add_val( tempBuffer, user );
}
if( domain != NULL )
{
kvbuf_add_key( tempBuffer, "domain" );
kvbuf_add_val( tempBuffer, domain );
}
}
nextValue:
if( (++idx) <= pAttrEntry->fAttributeValueCount )
{
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
dsGetAttributeValue( inNodeRef, inDataBuffer, idx, valueRef, &pValueEntry );
}
} while( idx <= pAttrEntry->fAttributeValueCount );
}
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
}
if ( valueRef != 0 )
{
dsCloseAttributeValueList( valueRef );
valueRef = 0;
}
if ( pAttrEntry != NULL )
{
dsDeallocAttributeEntry( inDirRef, pAttrEntry );
pAttrEntry = NULL;
}
}
kvbuf_append_kvbuf( inBuffer, tempBuffer );
if( inCache != NULL )
{
if( pSearch != NULL )
CCachePlugin::AddEntryToCacheWithMultiKey( inCache, valid_t, tempBuffer, CACHE_ENTRY_TYPE_GROUP, kCacheTime, "netgroup", name,
"host", pSearch[0], "user", pSearch[1], "domain", pSearch[2], NULL );
else
CCachePlugin::AddEntryToCacheWithMultiKey( inCache, valid_t, tempBuffer, CACHE_ENTRY_TYPE_GROUP, kCacheTime, "netgroup", name, NULL );
}
else
{
kvbuf_free( tempBuffer );
}
return valid_t;
}
sCacheValidation* ParseHostEntry( tDirReference inDirRef, tDirNodeReference inNodeRef, kvbuf_t *inBuffer, tDataBufferPtr inDataBuffer,
tRecordEntryPtr inRecEntry, tAttributeListRef inAttrListRef, void *additionalInfo, CCache *inCache,
const char **inKeys )
{
tAttributeValueListRef valueRef = 0;
tAttributeEntry *pAttrEntry = nil;
tAttributeValueEntry *pValueEntry = nil;
tDirStatus siResult;
kvbuf_t *tempBuffer = kvbuf_new_zone( malloc_default_purgeable_zone() );
sCacheValidation *valid_t = NULL;
kvbuf_add_dict( tempBuffer );
for (unsigned int i = 1; i <= inRecEntry->fRecordAttributeCount; i++)
{
siResult = dsGetAttributeEntry( inNodeRef, inDataBuffer, inAttrListRef, i, &valueRef, &pAttrEntry );
if ( ( siResult == eDSNoErr ) && ( pAttrEntry->fAttributeValueCount > 0 ) )
{
siResult = ::dsGetAttributeValue( inNodeRef, inDataBuffer, 1, valueRef, &pValueEntry );
if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrMetaNodeLocation ) == 0 )
{
if ( valid_t == NULL )
valid_t = new sCacheValidation( pValueEntry->fAttributeValueData.fBufferData );
}
else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrRecordName ) == 0 )
{
kvbuf_add_key( tempBuffer, "h_name" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
if( pAttrEntry->fAttributeValueCount > 1 )
kvbuf_add_key( tempBuffer, "h_aliases" );
for (UInt32 idx=2; idx <= pAttrEntry->fAttributeValueCount; idx++)
{
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
dsGetAttributeValue( inNodeRef, inDataBuffer, idx, valueRef, &pValueEntry );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
}
else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrIPAddress ) == 0 )
{
kvbuf_add_key( tempBuffer, "h_ipv4_addr_list" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
for (UInt32 idx=2; idx <= pAttrEntry->fAttributeValueCount; idx++)
{
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
dsGetAttributeValue( inNodeRef, inDataBuffer, idx, valueRef, &pValueEntry );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
}
else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrIPv6Address ) == 0 )
{
kvbuf_add_key( tempBuffer, "h_ipv6_addr_list" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
for (UInt32 idx=2; idx <= pAttrEntry->fAttributeValueCount; idx++)
{
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
dsGetAttributeValue( inNodeRef, inDataBuffer, idx, valueRef, &pValueEntry );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
}
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
}
if ( valueRef != 0 )
{
dsCloseAttributeValueList( valueRef );
valueRef = 0;
}
if ( pAttrEntry != NULL )
{
dsDeallocAttributeEntry( inDirRef, pAttrEntry );
pAttrEntry = NULL;
}
}
kvbuf_append_kvbuf( inBuffer, tempBuffer );
if( inCache != NULL && inKeys != NULL )
CCachePlugin::AddEntryToCacheWithKeys( inCache, NULL, tempBuffer, CACHE_ENTRY_TYPE_HOST, kCacheTime, inKeys );
else
kvbuf_free( tempBuffer );
return valid_t;
}
sCacheValidation* ParseEthernetEntry( tDirReference inDirRef, tDirNodeReference inNodeRef, kvbuf_t *inBuffer, tDataBufferPtr inDataBuffer,
tRecordEntryPtr inRecEntry, tAttributeListRef inAttrListRef, void *additionalInfo, CCache *inCache,
const char **inKeys )
{
tAttributeValueListRef valueRef = 0;
tAttributeEntry *pAttrEntry = nil;
tAttributeValueEntry *pValueEntry = nil;
tDirStatus siResult;
kvbuf_t *tempBuffer = kvbuf_new_zone( malloc_default_purgeable_zone() );
sCacheValidation *valid_t = NULL;
kvbuf_add_dict( tempBuffer );
for (unsigned int i = 1; i <= inRecEntry->fRecordAttributeCount; i++)
{
siResult = dsGetAttributeEntry( inNodeRef, inDataBuffer, inAttrListRef, i, &valueRef, &pAttrEntry );
if ( ( siResult == eDSNoErr ) && ( pAttrEntry->fAttributeValueCount > 0 ) )
{
siResult = ::dsGetAttributeValue( inNodeRef, inDataBuffer, 1, valueRef, &pValueEntry );
if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrMetaNodeLocation ) == 0 )
{
if ( valid_t == NULL )
valid_t = new sCacheValidation( pValueEntry->fAttributeValueData.fBufferData );
}
else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrRecordName ) == 0 )
{
kvbuf_add_key( tempBuffer, "name" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDS1AttrENetAddress ) == 0 )
{
kvbuf_add_key( tempBuffer, "mac" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
}
if ( valueRef != 0 )
{
dsCloseAttributeValueList( valueRef );
valueRef = 0;
}
if ( pAttrEntry != NULL )
{
dsDeallocAttributeEntry( inDirRef, pAttrEntry );
pAttrEntry = NULL;
}
}
kvbuf_append_kvbuf( inBuffer, tempBuffer );
if( inCache != NULL && inKeys != NULL )
CCachePlugin::AddEntryToCacheWithKeys( inCache, NULL, tempBuffer, CACHE_ENTRY_TYPE_HOST, kCacheTime, inKeys );
else
kvbuf_free( tempBuffer );
return( valid_t );
}
static struct ether_addr *myether_aton( const char *s, struct ether_addr *ep )
{
unsigned int t[6];
if (ep == NULL) return NULL;
int i = sscanf(s, " %x:%x:%x:%x:%x:%x", &t[0], &t[1], &t[2], &t[3], &t[4], &t[5]);
if (i != 6) return NULL;
for (i = 0; i < 6; i++)
ep->ether_addr_octet[i] = t[i];
return ep;
}
sCacheValidation* ParseBootpEntry( tDirReference inDirRef, tDirNodeReference inNodeRef, kvbuf_t *inBuffer, tDataBufferPtr inDataBuffer,
tRecordEntryPtr inRecEntry, tAttributeListRef inAttrListRef, void *additionalInfo, CCache *inCache,
const char **inKeys )
{
tAttributeValueListRef valueRef = 0;
tAttributeEntry *pAttrEntry = nil;
tAttributeValueEntry *pValueEntry = nil;
tDirStatus siResult;
kvbuf_t *tempBuffer = kvbuf_new_zone( malloc_default_purgeable_zone() );
sCacheValidation *valid_t = NULL;
bool bUsedPair = false;
bool bAddedFirst = false;
char **keys = (char **) additionalInfo;
kvbuf_add_dict( tempBuffer );
if ( keys != NULL )
{
for (unsigned int i = 1; i <= inRecEntry->fRecordAttributeCount && bUsedPair == false; i++)
{
siResult = dsGetAttributeEntry( inNodeRef, inDataBuffer, inAttrListRef, i, &valueRef, &pAttrEntry );
if ( siResult == eDSNoErr && pAttrEntry->fAttributeValueCount > 0 )
{
if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrIPAddressAndENetAddress ) == 0 )
{
for ( UInt32 ii = 1; ii <= pAttrEntry->fAttributeValueCount; ii++ )
{
siResult = ::dsGetAttributeValue( inNodeRef, inDataBuffer, ii, valueRef, &pValueEntry );
if ( siResult == eDSNoErr )
{
char *slash = strchr( pValueEntry->fAttributeValueData.fBufferData, '/' );
if ( slash != NULL )
{
bool bFoundMatch = false;
(*slash) = '\0';
slash++;
if ( keys[0] != NULL && strcmp(keys[0], pValueEntry->fAttributeValueData.fBufferData) == 0 )
bFoundMatch = true;
if ( bFoundMatch || keys[1] != NULL )
{
struct ether_addr etherStorage;
struct ether_addr *etherAddr = myether_aton( slash, ðerStorage );
char buffer[32];
if ( etherAddr != NULL )
{
snprintf( buffer, sizeof(buffer), "%02x:%02x:%02x:%02x:%02x:%02x", etherAddr->octet[0], etherAddr->octet[1],
etherAddr->octet[2], etherAddr->octet[3], etherAddr->octet[4], etherAddr->octet[5] );
if ( bFoundMatch || strcmp(keys[1], buffer) == 0 )
{
if ( bAddedFirst == false ) {
kvbuf_add_key( tempBuffer, "bp_hw" );
kvbuf_add_val( tempBuffer, buffer );
kvbuf_add_key( tempBuffer, "bp_addr" );
bAddedFirst = true;
}
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
bUsedPair = true;
}
}
}
}
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
}
}
}
if ( valueRef != 0 )
{
dsCloseAttributeValueList( valueRef );
valueRef = 0;
}
if ( pAttrEntry != NULL )
{
dsDeallocAttributeEntry( inDirRef, pAttrEntry );
pAttrEntry = NULL;
}
}
}
for (unsigned int i = 1; i <= inRecEntry->fRecordAttributeCount; i++)
{
siResult = dsGetAttributeEntry( inNodeRef, inDataBuffer, inAttrListRef, i, &valueRef, &pAttrEntry );
if ( ( siResult == eDSNoErr ) && ( pAttrEntry->fAttributeValueCount > 0 ) )
{
siResult = ::dsGetAttributeValue( inNodeRef, inDataBuffer, 1, valueRef, &pValueEntry );
if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrMetaNodeLocation ) == 0 )
{
if ( valid_t == NULL )
valid_t = new sCacheValidation( pValueEntry->fAttributeValueData.fBufferData );
}
else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrRecordName ) == 0 )
{
kvbuf_add_key( tempBuffer, "bp_name" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDS1AttrBootFile ) == 0 )
{
kvbuf_add_key( tempBuffer, "bp_bootfile" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
else if ( bUsedPair == false )
{
if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDS1AttrENetAddress ) == 0 )
{
UInt32 idx = 1;
kvbuf_add_key( tempBuffer, "bp_hw" );
while( 1 )
{
struct ether_addr etherStorage;
struct ether_addr *etherAddr = myether_aton( pValueEntry->fAttributeValueData.fBufferData, ðerStorage );
if( etherAddr != NULL )
{
char buffer[32];
snprintf( buffer, sizeof(buffer), "%02x:%02x:%02x:%02x:%02x:%02x", etherAddr->octet[0], etherAddr->octet[1], etherAddr->octet[2], etherAddr->octet[3], etherAddr->octet[4], etherAddr->octet[5] );
kvbuf_add_val( tempBuffer, buffer );
}
if( (++idx) <= pAttrEntry->fAttributeValueCount )
{
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
dsGetAttributeValue( inNodeRef, inDataBuffer, idx, valueRef, &pValueEntry );
continue;
}
break;
}
}
else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrIPAddress ) == 0 )
{
kvbuf_add_key( tempBuffer, "bp_addr" );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
for (UInt32 idx=2; idx <= pAttrEntry->fAttributeValueCount; idx++)
{
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
dsGetAttributeValue( inNodeRef, inDataBuffer, idx, valueRef, &pValueEntry );
kvbuf_add_val( tempBuffer, pValueEntry->fAttributeValueData.fBufferData );
}
}
}
if ( pValueEntry != NULL )
{
dsDeallocAttributeValueEntry( inDirRef, pValueEntry );
pValueEntry = NULL;
}
}
if ( valueRef != 0 )
{
dsCloseAttributeValueList( valueRef );
valueRef = 0;
}
if ( pAttrEntry != NULL )
{
dsDeallocAttributeEntry( inDirRef, pAttrEntry );
pAttrEntry = NULL;
}
}
kvbuf_append_kvbuf( inBuffer, tempBuffer );
if( inCache != NULL && inKeys != NULL )
CCachePlugin::AddEntryToCacheWithKeys( inCache, NULL, tempBuffer, CACHE_ENTRY_TYPE_COMPUTER, 60, inKeys );
else
kvbuf_free( tempBuffer );
return( valid_t );
}
#pragma mark -
#pragma mark Libinfo cache and support routines
#pragma mark -
void CCachePlugin::RemoveEntryWithMultiKey( CCache *inCache, ... )
{
char *key = NULL;
va_list args;
if (gDSInstallDaemonMode) return;
va_start( args, inCache );
while( 1 )
{
char *tempKey = va_arg( args, char * );
if( tempKey == NULL )
break;
const char *tempValue = va_arg( args, const char * );
if( tempValue == NULL )
tempValue = "";
int newLen = 0;
if( key != NULL )
{
newLen = strlen(key) + sizeof(" ") + strlen(tempKey) + sizeof(":") + strlen(tempValue) + 1;
key = (char *) reallocf( key, newLen );
strlcat( key, " ", newLen );
}
else
{
newLen = strlen(tempKey) + sizeof(":") + strlen(tempValue) + 1;
key = (char *) calloc( newLen, sizeof(char) );
}
strlcat( key, tempKey, newLen );
strlcat( key, ":", newLen );
strlcat( key, tempValue, newLen );
}
inCache->RemoveKey( key );
DbgLog( kLogPlugin, "CCachePlugin::RemoveEntryWithMultiKey - key %s", key );
DSFree( key );
}
void CCachePlugin::AddEntryToCacheWithMultiKey( CCache *inCache, sCacheValidation *inValidation, kvbuf_t *inEntry, uint32_t flags,
uint32_t inTTL, ... )
{
char *key = NULL;
va_list args;
if ( gDSInstallDaemonMode )
{
kvbuf_free( inEntry );
return;
}
va_start( args, inTTL );
while( 1 )
{
char *tempKey = va_arg( args, char * );
if( tempKey == NULL )
break;
const char *tempValue = va_arg( args, const char * );
if( tempValue == NULL )
tempValue = "";
int newLen = 0;
if( key != NULL )
{
newLen = strlen(key) + sizeof(" ") + strlen(tempKey) + sizeof(":") + strlen(tempValue) + 1;
key = (char *) reallocf( key, newLen );
strlcat( key, " ", newLen );
}
else
{
newLen = strlen(tempKey) + sizeof(":") + strlen(tempValue) + 1;
key = (char *) calloc( newLen, sizeof(char) );
}
strlcat( key, tempKey, newLen );
strlcat( key, ":", newLen );
strlcat( key, tempValue, newLen );
}
if ( inEntry != NULL )
{
sCacheEntry *cacheEntry = inCache->CreateEntry( inEntry, key, inTTL, flags );
if ( cacheEntry != NULL )
{
DbgLog( kLogPlugin, "CCachePlugin::AddEntryToCacheWithMultiKey - Entry added for record %X with key %s - TTL %d", inEntry, key,
inTTL );
cacheEntry->AddValidation( inValidation );
inCache->ReleaseEntry( cacheEntry ); }
else
{
kvbuf_free( inEntry );
DbgLog( kLogPlugin, "CCachePlugin::AddEntryToCacheWithMultiKey - Entry NOT added for record %X with key %s - collision", inEntry, key );
}
}
else
{
sCacheEntry *cacheEntry = inCache->CreateEntry( NULL, key, inTTL, (flags | CACHE_ENTRY_TYPE_NEGATIVE) );
if ( cacheEntry != NULL )
{
DbgLog( kLogPlugin, "CCachePlugin::AddEntryToCacheWithMultiKey - Negative cache entry for key %s - TTL %d", key, inTTL );
inCache->ReleaseEntry( cacheEntry ); }
}
DSFree( key );
}
void CCachePlugin::AddEntryToCacheWithKeylists( CCache *inCache, sCacheValidation *inValidation, kvbuf_t *inEntry, uint32_t flags,
uint32_t inTTL, ... )
{
va_list args;
sCacheEntry *cacheEntry = NULL;
if ( gDSInstallDaemonMode == true )
{
kvbuf_free( inEntry );
return;
}
va_start( args, inTTL );
kvarray_t *array = kvbuf_decode( inEntry );
if( array == NULL )
{
kvbuf_free( inEntry );
return;
}
kvdict_t *dict = array->dict;
uint32_t kcount = dict->kcount;
while( 1 )
{
char **keyList = va_arg( args, char ** );
uint32_t indexKeysCnt = 0;
char **indexKeys = NULL;
char **tempKeyList;
char *tempKey;
if( keyList == NULL )
break;
for( tempKeyList = keyList, tempKey = (*tempKeyList); tempKey != NULL; tempKeyList++, tempKey = (*tempKeyList) )
{
if( indexKeys == NULL )
{
for( uint32_t k = 0; k < kcount && indexKeys == NULL; k++ )
{
if( strcmp(dict->key[k], tempKey) == 0 )
{
indexKeysCnt = dict->vcount[k];
indexKeys = (char **) calloc( dict->vcount[k] + 1, sizeof(char *) );
for( uint32_t v = 0; v < indexKeysCnt; v++ )
{
const char *tempValue = dict->val[k][v];
int newLen = strlen(tempKey) + sizeof(":") + strlen(tempValue) + 1;
char *indexKey = (char *) calloc( newLen, sizeof(char) );
indexKeys[v] = indexKey;
strlcpy( indexKey, tempKey, newLen );
strlcat( indexKey, ":", newLen );
strlcat( indexKey, tempValue, newLen );
}
break;
}
}
if( indexKeysCnt == 0 )
break;
}
else
{
for( uint32_t k = 0; k < kcount; k++ )
{
if( strcmp(dict->key[k], tempKey) == 0 )
{
if( dict->vcount[k] > 0 )
{
const char *tempValue = dict->val[k][0];
int iTempKeyLen = strlen( tempKey );
int iTempValLen = strlen( tempValue );
for( uint32_t ii = 0; ii < indexKeysCnt; ii++ )
{
int newLen = strlen(indexKeys[ii]) + sizeof(" ") + iTempKeyLen + sizeof(":") + iTempValLen + 1;
char *indexKey = (char *) reallocf( indexKeys[ii], newLen );
indexKeys[ii] = indexKey;
strlcat( indexKey, " ", newLen );
strlcat( indexKey, tempKey, newLen );
strlcat( indexKey, ":", newLen );
strlcat( indexKey, tempValue, newLen );
}
}
break;
}
}
}
}
if( indexKeys != NULL )
{
for( uint32_t ii = 0; ii < indexKeysCnt; ii++ )
{
char *indexKey = indexKeys[ii];
if( indexKey != NULL )
{
if( cacheEntry != NULL )
{
inCache->AddKeyToEntry( cacheEntry, indexKey, TRUE );
DbgLog( kLogPlugin, "CCachePlugin::AddEntryToCacheWithKeylists - Entry %X added key %s", cacheEntry, indexKey );
}
else
{
cacheEntry = inCache->CreateEntry( inEntry, indexKey, inTTL, flags );
if ( cacheEntry != NULL )
{
DbgLog( kLogPlugin, "CCachePlugin::AddEntryToCacheWithKeylists - Entry %X added for record %X with key %s - TTL %d",
cacheEntry, inEntry, indexKey, inTTL );
cacheEntry->AddValidation( inValidation );
}
else
{
DbgLog( kLogPlugin, "CCachePlugin::AddEntryToCacheWithKeylists - Entry NOT added for record %X with key %s - collision",
inEntry, indexKey );
}
}
DSFree( indexKey );
indexKeys[ii] = NULL;
}
}
DSFree( indexKeys );
}
}
if ( cacheEntry != NULL ) {
inCache->ReleaseEntry( cacheEntry ); array->kv = NULL;
}
kvarray_free( array );
}
void CCachePlugin::AddEntryToCacheWithKeys( CCache *inCache, sCacheValidation *inValidation, kvbuf_t *inEntry, uint32_t flags, uint32_t inTTL,
const char **inKeysToIndex )
{
sCacheEntry *cacheEntry = NULL;
const char *key = NULL;
if ( gDSInstallDaemonMode == true )
{
kvbuf_free( inEntry );
return;
}
kvbuf_reset( inEntry );
uint32_t kcount = kvbuf_next_dict( inEntry );
for (uint32_t k = 0; k < kcount; k++)
{
uint32_t vcount = 0;
key = kvbuf_next_key( inEntry, &vcount );
if( key != NULL )
{
const char **keyList;
const char *tempKey;
for( keyList = inKeysToIndex, tempKey = (*keyList); *keyList != NULL; keyList++, tempKey = (*keyList) )
{
if( strcmp(key, tempKey) == 0 )
{
for (uint32_t v = 0; v < vcount; v++)
{
char *val = kvbuf_next_val( inEntry );
if( val != NULL )
{
int newLen = strlen(tempKey) + sizeof(":") + strlen(val) + 1;
char *indexedKey = (char *) malloc( newLen ); strlcpy( indexedKey, tempKey, newLen );
strlcat( indexedKey, ":", newLen );
strlcat( indexedKey, val, newLen );
if ( cacheEntry != NULL )
{
inCache->AddKeyToEntry( cacheEntry, indexedKey, TRUE );
DbgLog( kLogPlugin, "CCachePlugin::AddEntryToCacheWithKeys - Entry %X added key %s", cacheEntry, indexedKey );
}
else
{
cacheEntry = inCache->CreateEntry( inEntry, indexedKey, inTTL, flags );
if ( cacheEntry != NULL )
{
DbgLog( kLogPlugin, "CCachePlugin::AddEntryToCacheWithKeys - Entry %X added for record %X with key %s - TTL %d", cacheEntry,
inEntry, indexedKey, inTTL );
cacheEntry->AddValidation( inValidation );
}
else
{
DbgLog( kLogPlugin, "CCachePlugin::AddEntryToCacheWithKeys - Entry NOT added for record %X with key %s - collision",
inEntry, indexedKey );
}
}
DSFree( indexedKey );
}
}
}
}
}
}
if ( cacheEntry != NULL ) {
inCache->ReleaseEntry( cacheEntry ); } else {
kvbuf_free( inEntry );
}
}
kvbuf_t* CCachePlugin::FetchFromCache( CCache *inCache, uint32_t reqFlags, int32_t *outTTL, ... )
{
kvbuf_t *outBuffer = NULL;
char *key = NULL;
va_list args;
if (gDSInstallDaemonMode) return NULL;
va_start( args, outTTL );
while( 1 )
{
char *tempKey = va_arg( args, char * );
if( tempKey == NULL )
break;
const char *tempValue = va_arg( args, const char * );
if( tempValue == NULL )
tempValue = "";
int newLen = 0;
if( key != NULL )
{
newLen = strlen(key) + sizeof(" ") + strlen(tempKey) + sizeof(":") + strlen(tempValue) + 1;
key = (char *) reallocf( key, newLen );
strlcat( key, " ", newLen );
}
else
{
newLen = strlen(tempKey) + sizeof(":") + strlen(tempValue) + 1;
key = (char *) calloc( newLen, sizeof(char) );
}
strlcat( key, tempKey, newLen );
strlcat( key, ":", newLen );
strlcat( key, tempValue, newLen );
}
DbgLog( kLogDebug, "CCachePlugin::FetchFromCache - Looking for entry with key %s", key );
outBuffer = inCache->Fetch( key, outTTL, reqFlags );
DSFree( key );
fStatsLock.WaitLock();
if( outBuffer != NULL )
fCacheHits++;
else
fCacheMisses++;
fStatsLock.SignalLock();
return outBuffer;
}
kvbuf_t* CCachePlugin::GetRecordListLibInfo( tDirNodeReference inNodeRef, const char* inSearchValue, const char* inRecordType,
UInt32 inRecCount, tDataListPtr inAttributes, ProcessEntryCallback inCallback,
kvbuf_t* inBuffer, void *additionalInfo, CCache *inCache, const char **inKeys,
sCacheValidation **outValidation)
{
kvbuf_t *outBuffer = inBuffer;
tDataListPtr recName = NULL;
tDataListPtr recType = NULL;
tDataBufferPtr dataBuff = NULL;
SInt32 siResult = eDSNoErr;
tContextData context = NULL;
tRecordEntry *pRecEntry = nil;
tAttributeListRef attrListRef = 0;
tDataListPtr nodeName = NULL;
uint32_t total = 0;
sCacheValidation *valid_t = NULL;
recName = dsBuildListFromStrings( fDirRef, inSearchValue, NULL );
recType = dsBuildListFromStrings( fDirRef, inRecordType, NULL );
dataBuff = dsDataBufferAllocate( fDirRef, 8192 );
do
{
siResult = dsGetRecordList( inNodeRef,
dataBuff,
recName,
eDSiExact,
recType,
inAttributes,
false,
&inRecCount,
&context);
if (siResult == eDSBufferTooSmall)
{
UInt32 bufSize = dataBuff->fBufferSize;
dsDataBufferDeallocatePriv( dataBuff );
dataBuff = nil;
dataBuff = dsDataBufferAllocate( fDirRef, bufSize * 2 );
}
if ( (siResult == eDSNoErr) && (inRecCount > 0) )
{
total += inRecCount;
if ( outBuffer == NULL )
outBuffer = kvbuf_new();
for( unsigned int ii = 1; ii <= inRecCount; ii++ )
{
siResult = ::dsGetRecordEntry( inNodeRef, dataBuff, ii, &attrListRef, &pRecEntry );
if ( (siResult == eDSNoErr) && (pRecEntry != nil) )
{
valid_t = inCallback( fDirRef, inNodeRef, outBuffer, dataBuff, pRecEntry, attrListRef, additionalInfo, inCache, inKeys );
if ( outValidation != NULL ) {
(*outValidation) = valid_t;
}
else {
DSRelease( valid_t );
}
}
if (attrListRef != 0)
{
dsCloseAttributeList( attrListRef );
attrListRef = 0;
}
if (pRecEntry != NULL)
{
dsDeallocRecordEntry( fDirRef, pRecEntry );
pRecEntry = nil;
}
}
}
if ( siResult == eDSInvalidContext || siResult == eDSInvalidContinueData || siResult == eDSBadContextData ) {
kvbuf_free( outBuffer );
outBuffer = NULL;
context = 0;
siResult = eDSBadContextData; }
} while ( siResult == eDSBufferTooSmall || (siResult == eDSNoErr && context != 0) || siResult == eDSBadContextData );
if ( siResult == eDSNoErr )
{
DbgLog( kLogDebug, "CCachePlugin::GetRecordListLibInfo - Found %u total results", total );
}
else
{
DbgLog( kLogDebug, "CCachePlugin::GetRecordListLibInfo - Error on search <%d>", siResult);
}
if ( recName != NULL )
{
dsDataListDeallocate( fDirRef, recName );
DSFree( recName );
}
if ( recType != NULL )
{
dsDataListDeallocate( fDirRef, recType );
DSFree( recType );
}
if ( dataBuff != NULL )
{
dsDataBufferDeAllocate( fDirRef, dataBuff );
dataBuff = NULL;
}
if ( nodeName != NULL )
{
dsDataListDeallocate( fDirRef, nodeName );
DSFree( nodeName );
}
return( outBuffer );
}
kvbuf_t* CCachePlugin::ValueSearchLibInfo( tDirNodeReference inNodeRef, const char* inSearchAttrib, const char* inSearchValue,
const char* inRecordType, UInt32 inRecCount, tDataListPtr inAttributes,
ProcessEntryCallback inCallback, kvbuf_t* inBuffer, void *additionalInfo,
sCacheValidation **outValidation, tDirPatternMatch inSearchType )
{
kvbuf_t *outBuffer = inBuffer;
tDataNodePtr pattMatch = NULL;
tDataListPtr recType = NULL;
tDataNodePtr attrMatchType = NULL;
tDataBufferPtr dataBuff = NULL;
SInt32 siResult = eDSNoErr;
tContextData context = NULL;
tRecordEntry *pRecEntry = nil;
tAttributeListRef attrListRef = 0;
try
{
pattMatch = dsDataNodeAllocateString( fDirRef, inSearchValue );
attrMatchType = dsDataNodeAllocateString( fDirRef, inSearchAttrib );
recType = dsBuildListFromStrings( fDirRef, inRecordType, NULL );
dataBuff = dsDataBufferAllocate( fDirRef, 8192 );
do
{
siResult = dsDoAttributeValueSearchWithData( inNodeRef,
dataBuff,
recType,
attrMatchType,
inSearchType,
pattMatch,
inAttributes,
false,
&inRecCount,
&context);
if (siResult == eDSBufferTooSmall)
{
UInt32 bufSize = dataBuff->fBufferSize;
dsDataBufferDeallocatePriv( dataBuff );
dataBuff = nil;
dataBuff = dsDataBufferAllocate( fDirRef, bufSize * 2 );
}
if ( (siResult == eDSNoErr) && (inRecCount > 0) )
{
if ( outBuffer == NULL )
outBuffer = kvbuf_new();
for( unsigned int ii = 1; ii <= inRecCount; ii++ )
{
siResult = ::dsGetRecordEntry( inNodeRef, dataBuff, ii, &attrListRef, &pRecEntry );
if ( (siResult == eDSNoErr) && (pRecEntry != nil) )
{
sCacheValidation *tempValid_t = NULL;
tempValid_t = inCallback( fDirRef, inNodeRef, outBuffer, dataBuff, pRecEntry, attrListRef, additionalInfo, NULL, NULL );
if (outValidation != NULL && *outValidation == NULL) {
*outValidation = tempValid_t;
}
else {
DSRelease( tempValid_t );
}
}
if( attrListRef != 0 )
{
dsCloseAttributeList(attrListRef);
attrListRef = 0;
}
if (pRecEntry != nil)
{
dsDeallocRecordEntry(fDirRef, pRecEntry);
pRecEntry = nil;
}
}
}
if ( siResult == eDSInvalidContext || siResult == eDSInvalidContinueData || siResult == eDSBadContextData ) {
kvbuf_free( outBuffer );
outBuffer = NULL;
context = 0;
siResult = eDSBadContextData; }
} while ( siResult == eDSBufferTooSmall || (siResult == eDSNoErr && context != 0) || siResult == eDSBadContextData );
}
catch( SInt32 err )
{
}
if ( pattMatch != NULL )
{
dsDataBufferDeAllocate( fDirRef, pattMatch );
pattMatch = NULL;
}
if ( recType != NULL )
{
dsDataListDeallocate( fDirRef, recType );
DSFree( recType );
}
if ( attrMatchType != NULL )
{
dsDataBufferDeAllocate( fDirRef, attrMatchType );
attrMatchType = NULL;
}
if ( dataBuff != NULL )
{
dsDataBufferDeAllocate( fDirRef, dataBuff );
dataBuff = NULL;
}
return( outBuffer );
}
#pragma mark -
#pragma mark Libinfo Support routines
#pragma mark -
#ifdef HANDLE_DNS_LOOKUPS
void CCachePlugin::checkAAAAstatus( void )
{
struct ifaddrs *ifa, *ifap;
sa_family_t family;
struct sockaddr_in6 *sin6;
bool isLinkLocal, isLoopback;
if (getifaddrs(&ifa) != 0) return;
__sync_bool_compare_and_swap( &aaaa_cutoff_enabled, false, true );
if (fAlwaysDoAAAA) return;
for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next)
{
family = ifap->ifa_addr->sa_family;
if (family == AF_INET6)
{
sin6 = (struct sockaddr_in6 *)(ifap->ifa_addr);
isLinkLocal = (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) != 0);
isLoopback = (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr) != 0);
if ((!isLinkLocal) && (!isLoopback)) __sync_bool_compare_and_swap( &aaaa_cutoff_enabled, true, false );
}
}
freeifaddrs(ifa);
DbgLog( kLogDebug, "CCachePlugin::checkAAAAstatus - %s AAAA queries", (aaaa_cutoff_enabled ? "skipping" : "not skipping") );
}
int AddToDNSThreads( void )
{
int slot = -1;
int ii;
int rc = pthread_mutex_lock( &gActiveThreadMutex );
if ( rc != 0 )
{
DbgLog( kLogCritical, "CCachePlugin::AddToDNSThreads - pthread_mutex_lock failed %s (%d). Aborting",
strerror(rc), rc);
abort();
}
for( ii = 0; ii < gActiveThreadCount; ii++ )
{
if( gActiveThreads[ii] == NULL )
{
slot = ii;
break;
}
}
if( slot == -1 && gActiveThreadCount < 512 )
{
slot = gActiveThreadCount;
gActiveThreadCount++;
}
if ( slot != -1 )
{
gActiveThreads[slot] = pthread_self();
gInterruptTokens[slot] = res_init_interrupt_token();
DbgLog( kLogDebug, "CCachePlugin::AddToDNSThreads called added thread %X to slot %d token %X",
(unsigned long) gActiveThreads[slot], slot, gInterruptTokens[slot] );
}
else
{
DbgLog( kLogDebug, "CCachePlugin::AddToDNSThreads called no slots available to add thread %X ", (unsigned long) pthread_self() );
}
rc = pthread_mutex_unlock( &gActiveThreadMutex );
if ( rc != 0 )
{
DbgLog( kLogCritical, "CCachePlugin::AddToDNSThreads - pthread_mutex_unlock failed %s (%d). Aborting",
strerror(rc), rc);
abort();
}
return slot;
}
bool RemoveFromDNSThreads( int inSlot )
{
bool bReturn = false;
if( inSlot == -1 )
{
DbgLog( kLogDebug, "CCachePlugin::RemoveFromDNSThreads called for slot with -1" );
return bReturn;
}
int rc = pthread_mutex_lock( &gActiveThreadMutex );
if ( rc != 0 )
{
DbgLog( kLogCritical, "CCachePlugin::RemoveFromDNSThreads - pthread_mutex_lock failed %s (%d). Aborting",
strerror(rc), rc);
abort();
}
DbgLog( kLogDebug, "CCachePlugin::RemoveFromDNSThreads called for slot %d = %X", inSlot, (unsigned long) gActiveThreads[inSlot] );
gActiveThreads[inSlot] = NULL;
if( gNotifyTokens[inSlot] != 0 )
{
if ( gThreadAbandon[inSlot] == false ) bReturn = true;
else
DbgLog( kLogDebug, "CCachePlugin::RemoveFromDNSThreads lookup abandoned for slot %d not retrying", inSlot );
notify_cancel( gNotifyTokens[inSlot] );
DbgLog( kLogDebug, "CCachePlugin::RemoveFromDNSThreads cancelling notify token %d", gNotifyTokens[inSlot] );
gNotifyTokens[inSlot] = 0;
gThreadAbandon[inSlot] = false;
}
if ( gInterruptTokens[inSlot] != NULL )
{
DbgLog( kLogDebug, "CCachePlugin::RemoveFromDNSThreads deleting interrupt token %X", gInterruptTokens[inSlot] );
res_delete_interrupt_token( gInterruptTokens[inSlot] );
gInterruptTokens[inSlot] = NULL;
}
rc = pthread_mutex_unlock( &gActiveThreadMutex );
if ( rc != 0 )
{
DbgLog( kLogCritical, "CCachePlugin::RemoveFromDNSThreads - pthread_mutex_unlock failed %s (%d). Aborting",
strerror(rc), rc);
abort();
}
return bReturn;
}
void CancelDNSThreads( void )
{
int rc = pthread_mutex_lock( &gActiveThreadMutex );
if ( rc != 0 )
{
DbgLog( kLogCritical, "CCachePlugin::CancelDNSThreads - pthread_mutex_lock failed %s (%d). Aborting",
strerror(rc), rc);
abort();
}
int numThreadsCancelled = 0;
for( int ii = 0; ii < gActiveThreadCount; ii++ )
{
if( gActiveThreads[ii] != NULL && gNotifyTokens[ii] == 0 )
{
char notify_name[128];
int notify_token = 0;
snprintf(notify_name, sizeof(notify_name), "self.thread.%lu", (unsigned long) gActiveThreads[ii]);
int status = notify_register_plain(notify_name, ¬ify_token);
if (status == NOTIFY_STATUS_OK)
{
notify_set_state(notify_token, ThreadStateExitRequested);
gNotifyTokens[ii] = notify_token;
DbgLog( kLogDebug, "CCachePlugin::CancelDNSThreads called for slot %d notification '%s' token %X",
ii, notify_name, gInterruptTokens[ii] );
res_interrupt_request( gInterruptTokens[ii] );
++numThreadsCancelled;
}
}
}
DbgLog( kLogDebug, "CCachePlugin::CancelDNSThreads %d threads cancelled", numThreadsCancelled );
rc = pthread_mutex_unlock( &gActiveThreadMutex );
if ( rc != 0 )
{
DbgLog( kLogCritical, "CCachePlugin::CancelDNSThreads - pthread_mutex_unlock failed %s (%d). Aborting",
strerror(rc), rc);
abort();
}
}
void DoDNSQuery( void *context )
{
sDNSQuery *theQuery = (sDNSQuery *) context;
sDNSLookup *lookup = theQuery->fLookupEntry;
int index = theQuery->fQueryIndex;
double endTime = 0.0;
dns_handle_t dns = NULL;
dns_reply_t *dnsReply = NULL;
lookup->fThreadID[index] = pthread_self();
lookupAgain:
int slot = AddToDNSThreads();
if ( slot >= 0 )
{
dns = gDNSHandles[slot];
if ( dns == NULL )
{
dns = dns_open( NULL );
gDNSHandles[slot] = dns;
DbgLog( kLogDebug, "CCachePlugin::DoDNSQuery - Created a new dns handle for slot %d", slot );
}
if ( dns->sdns != NULL && aaaa_cutoff_enabled )
{
dns->sdns->flags |= DNS_FLAG_OK_TO_SKIP_AAAA;
DbgLog( kLogDebug, "CCachePlugin::DoDNSQuery - Index %d enabling DNS_FLAG_OK_TO_SKIP_AAAA", index );
}
dns_set_buffer_size( dns, 8192 );
lookup->fMinimumTTL[index] = -1;
double startTime = dsTimestamp();
dnsReply = idna_dns_lookup( dns, lookup->fQueryStrings[index], lookup->fQueryClasses[index], lookup->fQueryTypes[index],
&(lookup->fMinimumTTL[index]) );
endTime = dsTimestamp() - startTime;
if ( RemoveFromDNSThreads(slot) == true )
{
if ( dnsReply != NULL )
{
dns_free_reply( dnsReply );
dnsReply = NULL;
}
goto lookupAgain;
}
DbgLog( kLogPlugin, "CCachePlugin::DoDNSQuery - Index %d got %d answer(s) for %s type %d minTTL %d - %d ms", index,
(dnsReply ? dnsReply->header->ancount : 0), lookup->fQueryStrings[index], lookup->fQueryTypes[index], lookup->fMinimumTTL[index],
(int) (endTime / 1000.0) );
}
lookup->fAnswers[index] = dnsReply;
lookup->fAnswerTime[index] = endTime;
lookup->fThreadID[index] = NULL; __sync_bool_compare_and_swap( &(lookup->fQueryFinished[index]), false, true );
DbgLog( kLogDebug, "CCachePlugin::DoDNSQuery - Index %d, Outstanding = %d, Total = %d", index,
__sync_sub_and_fetch(&lookup->fOutstanding, 1), lookup->fTotal );
}
#endif
bool CCachePlugin::IsLocalOnlyPID( pid_t inPID )
{
bool bReturn = false;
fPIDListLock.WaitLock();
if ( fLocalOnlyPIDs.find(inPID) != fLocalOnlyPIDs.end() )
bReturn = true;
fPIDListLock.SignalLock();
return bReturn;
}
#pragma mark -
#pragma mark Libinfo API implementation routines
#pragma mark -
kvbuf_t* CCachePlugin::DSgetpwnam( kvbuf_t *inBuffer, pid_t inPID )
{
static tDataListPtr attrTypes = NULL;
static dispatch_once_t initAttrTypes = 0;
dispatch_once( &initAttrTypes,
^(void) {
attrTypes = dsBuildListFromStringsPriv( kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
kDS1AttrPassword,
kDS1AttrUniqueID,
kDS1AttrGeneratedUID,
kDS1AttrPrimaryGroupID,
kDS1AttrNFSHomeDirectory,
kDS1AttrUserShell,
kDS1AttrDistinguishedName,
kDSNAttrKeywords,
NULL );
} );
return DSgetpwnam_int( inBuffer, inPID, 0, attrTypes );
}
static tDataListPtr gExtUserAttrTypes = NULL;
void CCachePlugin::DSgetpwnam_initext( kvbuf_t *inBuffer, pid_t inPID )
{
static dispatch_once_t initAttrTypes = 0;
dispatch_once( &initAttrTypes,
^(void){
uint32_t ::dictCount = kvbuf_reset( inBuffer );
uint32_t ::valCount = 0;
if ( dictCount == 0 )
return;
gExtUserAttrTypes = dsBuildListFromStringsPriv( kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
kDS1AttrPassword,
kDS1AttrUniqueID,
kDS1AttrGeneratedUID,
kDS1AttrPrimaryGroupID,
kDS1AttrNFSHomeDirectory,
kDS1AttrUserShell,
kDS1AttrDistinguishedName,
kDSNAttrKeywords,
NULL );
kvbuf_next_dict( inBuffer );
if ( dictCount != 0 ) {
char *::key = kvbuf_next_key( inBuffer, &valCount );
uint32_t ::ii;
for ( ii = 0; ii < valCount; ii++ ) {
const char *::value = kvbuf_next_val( inBuffer );
if ( strncmp(value, kDSStdAttrTypePrefix, sizeof(kDSStdAttrTypePrefix)-1) == 0 ) {
dsAppendStringToListPriv( gExtUserAttrTypes, value );
}
}
}
} );
}
kvbuf_t* CCachePlugin::DSgetpwnam_ext( kvbuf_t *inBuffer, pid_t inPID )
{
kvbuf_t *outBuffer = NULL;
if ( gExtUserAttrTypes != NULL ) {
outBuffer = DSgetpwnam_int( inBuffer, inPID, CACHE_ENTRY_TYPE_EXTENDED, gExtUserAttrTypes );
}
return outBuffer;
}
kvbuf_t* CCachePlugin::DSgetpwnam_int( kvbuf_t *inBuffer, pid_t inPID, uint32_t reqFlags, tDataListPtr attrTypes )
{
kvbuf_t *outBuffer = NULL;
uint32_t dictCount = kvbuf_reset( inBuffer );
uint32_t valCount = 0;
if( dictCount == 0 )
return NULL;
kvbuf_next_dict( inBuffer );
char *key = kvbuf_next_key( inBuffer, &valCount );
if( strcmp(key, "login") != 0 || valCount == 0 )
return NULL;
char *name = kvbuf_next_val( inBuffer );
if( name == NULL )
return NULL;
outBuffer = FetchFromCache( fLibinfoCache, reqFlags, NULL, "pw_name", name, NULL );
if ( outBuffer == NULL ) {
outBuffer = FetchFromCache( fLibinfoCache, reqFlags, NULL, "pw_gecos", name, NULL );
}
if ( outBuffer == NULL )
{
if ( attrTypes != NULL )
{
const char *keys[] = { "pw_name", "pw_uid", "pw_gecos", NULL };
bool localOnlyPID = IsLocalOnlyPID( inPID );
if( localOnlyPID == false )
{
outBuffer = GetRecordListLibInfo( fSearchNodeRef, name, kDSStdRecordTypeUsers, 1, attrTypes, ParsePasswdEntry, NULL,
&reqFlags, fLibinfoCache, keys );
}
else
{
outBuffer = GetRecordListLibInfo( fLocalNodeRef, name, kDSStdRecordTypeUsers, 1, attrTypes, ParsePasswdEntry, NULL,
&reqFlags, fLibinfoCache, keys );
if( NULL == outBuffer )
{
outBuffer = GetRecordListLibInfo( fFlatFileNodeRef, name, kDSStdRecordTypeUsers, 1, attrTypes, ParsePasswdEntry, NULL,
&reqFlags, fLibinfoCache, keys );
}
}
if( outBuffer != NULL )
{
uint32_t dcount = kvbuf_reset( outBuffer );
if( dcount != 1 )
{
kvbuf_free( outBuffer );
outBuffer = NULL;
}
}
if( outBuffer == NULL && localOnlyPID == false ) {
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, NULL, CACHE_ENTRY_TYPE_USER | reqFlags, kNegativeCacheTime, "pw_name", name, NULL );
}
}
fStatsLock.WaitLock();
fCacheMissByFunction[kDSLUgetpwnam] += 1;
fStatsLock.SignalLock();
}
else
{
fStatsLock.WaitLock();
fCacheHitsByFunction[kDSLUgetpwnam] += 1;
fStatsLock.SignalLock();
DbgLog( kLogPlugin, "CCachePlugin::getpwnam - Cache hit for %s", name );
}
return( outBuffer );
}
kvbuf_t* CCachePlugin::DSgetpwuuid ( kvbuf_t *inBuffer, pid_t inPID )
{
kvbuf_t *outBuffer = NULL;
tDataListPtr attrTypes = NULL;
uint32_t dictCount = kvbuf_reset( inBuffer );
uint32_t valCount = 0;
sCacheValidation *theValidation = NULL;
if( dictCount == 0 )
return NULL;
kvbuf_next_dict( inBuffer );
char *key = kvbuf_next_key( inBuffer, &valCount );
if( strcmp(key, "uuid") != 0 || valCount == 0 )
return NULL;
char *number = kvbuf_next_val( inBuffer );
if( number == NULL )
return NULL;
outBuffer = FetchFromCache( fLibinfoCache, 0, NULL, "pw_uuid", number, NULL );
if ( outBuffer == NULL )
{
attrTypes = dsBuildListFromStrings( fDirRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
kDS1AttrPassword,
kDS1AttrUniqueID,
kDS1AttrGeneratedUID,
kDS1AttrPrimaryGroupID,
kDS1AttrNFSHomeDirectory,
kDS1AttrUserShell,
kDS1AttrDistinguishedName,
NULL );
if ( attrTypes != NULL )
{
bool localOnlyPID = IsLocalOnlyPID( inPID );
if( localOnlyPID == false )
{
outBuffer = ValueSearchLibInfo( fSearchNodeRef, kDS1AttrGeneratedUID, number, kDSStdRecordTypeUsers, 1, attrTypes, ParsePasswdEntry,
NULL, NULL, &theValidation );
}
else
{
outBuffer = ValueSearchLibInfo( fLocalNodeRef, kDS1AttrGeneratedUID, number, kDSStdRecordTypeUsers, 1, attrTypes, ParsePasswdEntry,
NULL, NULL, &theValidation );
if( NULL == outBuffer )
{
outBuffer = ValueSearchLibInfo( fFlatFileNodeRef, kDS1AttrGeneratedUID, number, kDSStdRecordTypeUsers, 1, attrTypes, ParsePasswdEntry,
NULL, NULL, &theValidation );
}
}
if( outBuffer != NULL )
{
uint32_t dcount = kvbuf_reset( outBuffer );
const char *keys[] = { "pw_name", "pw_uid", "pw_uuid", NULL };
if( dcount == 1 )
{
kvbuf_t *copy = kvbuf_init_zone( malloc_default_purgeable_zone(), outBuffer->databuf, outBuffer->datalen );
AddEntryToCacheWithKeys( fLibinfoCache, theValidation, copy, CACHE_ENTRY_TYPE_USER, kCacheTime, keys );
}
else
{
kvbuf_free( outBuffer );
outBuffer = NULL;
}
}
if( outBuffer == NULL && localOnlyPID == false ) {
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, NULL, CACHE_ENTRY_TYPE_USER, kNegativeCacheTime, "pw_uuid", number, NULL );
}
dsDataListDeallocate( fDirRef, attrTypes );
DSFree( attrTypes );
}
fStatsLock.WaitLock();
fCacheMissByFunction[kDSLUgetpwuuid] += 1;
fStatsLock.SignalLock();
}
else
{
fStatsLock.WaitLock();
fCacheHitsByFunction[kDSLUgetpwuuid] += 1;
fStatsLock.SignalLock();
DbgLog( kLogPlugin, "CCachePlugin::getpwuuid - Cache hit for %s", number );
}
DSRelease( theValidation );
return( outBuffer );
}
kvbuf_t* CCachePlugin::DSgetpwuid ( kvbuf_t *inBuffer, pid_t inPID )
{
kvbuf_t *outBuffer = NULL;
tDataListPtr attrTypes = NULL;
uint32_t dictCount = kvbuf_reset( inBuffer );
uint32_t valCount = 0;
sCacheValidation *theValidation = NULL;
if( dictCount == 0 )
return NULL;
kvbuf_next_dict( inBuffer );
char *key = kvbuf_next_key( inBuffer, &valCount );
if( strcmp(key, "uid") != 0 || valCount == 0 )
return NULL;
char *number = kvbuf_next_val( inBuffer );
if( number == NULL )
return NULL;
outBuffer = FetchFromCache( fLibinfoCache, 0, NULL, "pw_uid", number, NULL );
if ( outBuffer == NULL )
{
attrTypes = dsBuildListFromStrings( fDirRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
kDS1AttrPassword,
kDS1AttrUniqueID,
kDS1AttrPrimaryGroupID,
kDS1AttrNFSHomeDirectory,
kDS1AttrUserShell,
kDS1AttrDistinguishedName,
NULL );
if ( attrTypes != NULL )
{
const char *keys[] = { "pw_name", "pw_uid", NULL };
bool localOnlyPID = IsLocalOnlyPID( inPID );
if( localOnlyPID == false )
{
outBuffer = ValueSearchLibInfo( fSearchNodeRef, kDS1AttrUniqueID, number, kDSStdRecordTypeUsers, 1, attrTypes, ParsePasswdEntry,
NULL, NULL, &theValidation );
}
else
{
outBuffer = ValueSearchLibInfo( fLocalNodeRef, kDS1AttrUniqueID, number, kDSStdRecordTypeUsers, 1, attrTypes, ParsePasswdEntry,
NULL, NULL, &theValidation );
if( NULL == outBuffer )
{
outBuffer = ValueSearchLibInfo( fFlatFileNodeRef, kDS1AttrUniqueID, number, kDSStdRecordTypeUsers, 1, attrTypes, ParsePasswdEntry,
NULL, NULL, &theValidation );
}
}
if( outBuffer != NULL )
{
uint32_t dcount = kvbuf_reset( outBuffer );
if( dcount == 1 )
{
kvbuf_t *copy = kvbuf_init_zone( malloc_default_purgeable_zone(), outBuffer->databuf, outBuffer->datalen );
AddEntryToCacheWithKeys( fLibinfoCache, theValidation, copy, CACHE_ENTRY_TYPE_USER, kCacheTime, keys );
}
else
{
kvbuf_free( outBuffer );
outBuffer = NULL;
}
}
if ( outBuffer == NULL && localOnlyPID == false ) {
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, NULL, CACHE_ENTRY_TYPE_USER, kNegativeCacheTime, "pw_uid", number, NULL );
}
dsDataListDeallocate( fDirRef, attrTypes );
DSFree( attrTypes );
}
fStatsLock.WaitLock();
fCacheMissByFunction[kDSLUgetpwuid] += 1;
fStatsLock.SignalLock();
}
else
{
fStatsLock.WaitLock();
fCacheHitsByFunction[kDSLUgetpwuid] += 1;
fStatsLock.SignalLock();
DbgLog( kLogPlugin, "CCachePlugin::getpwuid - Cache hit for %s", number );
}
DSRelease( theValidation );
return( outBuffer );
}
kvbuf_t* CCachePlugin::DSgetpwent( void )
{
kvbuf_t *outBuffer = NULL;
tDataListPtr attrTypes = NULL;
outBuffer = FetchFromCache( fLibinfoCache, 0, NULL, "pwent", "1", NULL );
if ( outBuffer == NULL )
{
attrTypes = dsBuildListFromStrings( fDirRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
kDS1AttrPassword,
kDS1AttrUniqueID,
kDS1AttrGeneratedUID,
kDS1AttrPrimaryGroupID,
kDS1AttrNFSHomeDirectory,
kDS1AttrUserShell,
kDS1AttrDistinguishedName,
NULL );
if ( attrTypes != NULL )
{
outBuffer = GetRecordListLibInfo( fSearchNodeRef, kDSRecordsAll, kDSStdRecordTypeUsers, 0, attrTypes, ParsePasswdEntry, NULL, NULL,
NULL, NULL );
dsDataListDeallocate( fDirRef, attrTypes );
DSFree( attrTypes );
}
if ( outBuffer != NULL ) {
kvbuf_t *copy = kvbuf_init_zone( malloc_default_purgeable_zone(), outBuffer->databuf, outBuffer->datalen );
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, copy, CACHE_ENTRY_TYPE_USER, kEnumerationCacheTime, "pwent", "1", NULL );
}
}
return( outBuffer );
}
kvbuf_t* CCachePlugin::DSgetgrnam( kvbuf_t *inBuffer, pid_t inPID )
{
static tDataListPtr attrTypes = NULL;
static dispatch_once_t initAttrTypes = 0;
dispatch_once( &initAttrTypes,
^(void) {
attrTypes = dsBuildListFromStringsPriv( kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
kDS1AttrPassword,
kDS1AttrPrimaryGroupID,
kDS1AttrGeneratedUID,
kDSNAttrGroupMembership,
NULL );
} );
return DSgetgrnam_int( inBuffer, inPID, 0, attrTypes );
}
static tDataListPtr gExtGroupAttrTypes = NULL;
void CCachePlugin::DSgetgrnam_initext( kvbuf_t *inBuffer, pid_t inPID )
{
static dispatch_once_t initAttrTypes = 0;
dispatch_once( &initAttrTypes,
^(void){
uint32_t ::dictCount = kvbuf_reset( inBuffer );
uint32_t ::valCount = 0;
if ( dictCount == 0 )
return;
gExtGroupAttrTypes = dsBuildListFromStringsPriv( kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
kDS1AttrPassword,
kDS1AttrPrimaryGroupID,
kDS1AttrGeneratedUID,
kDSNAttrGroupMembership,
NULL );
kvbuf_next_dict( inBuffer );
if ( dictCount != 0 ) {
char *::key = kvbuf_next_key( inBuffer, &valCount );
uint32_t ::ii;
for ( ii = 0; ii < valCount; ii++ ) {
const char *::value = kvbuf_next_val( inBuffer );
if ( strncmp(value, kDSStdAttrTypePrefix, sizeof(kDSStdAttrTypePrefix)-1) == 0 ) {
dsAppendStringToListPriv( gExtGroupAttrTypes, value );
}
}
}
} );
}
kvbuf_t* CCachePlugin::DSgetgrnam_ext( kvbuf_t *inBuffer, pid_t inPID )
{
kvbuf_t * outBuffer = NULL;
if ( gExtGroupAttrTypes != NULL ) {
outBuffer = DSgetgrnam_int( inBuffer, inPID, CACHE_ENTRY_TYPE_EXTENDED, gExtGroupAttrTypes );
}
return outBuffer;
}
kvbuf_t* CCachePlugin::DSgetgrnam_int( kvbuf_t *inBuffer, pid_t inPID, uint32_t reqFlags, const tDataListPtr attrTypes )
{
kvbuf_t *outBuffer = NULL;
uint32_t dictCount = kvbuf_reset( inBuffer );
uint32_t valCount = 0;
if( dictCount == 0 )
return NULL;
kvbuf_next_dict( inBuffer );
char *key = kvbuf_next_key( inBuffer, &valCount );
if( strcmp(key, "name") != 0 || valCount == 0 )
return NULL;
char *name = kvbuf_next_val( inBuffer );
if( name == NULL )
return NULL;
outBuffer = FetchFromCache( fLibinfoCache, reqFlags, NULL, "gr_name", name, NULL );
if ( outBuffer == NULL )
{
if ( attrTypes != NULL )
{
const char *keys[] = { "gr_name", "gr_gid", "gr_uuid", NULL };
bool localOnlyPID = IsLocalOnlyPID( inPID );
if( localOnlyPID == false )
{
outBuffer = GetRecordListLibInfo( fSearchNodeRef, name, kDSStdRecordTypeGroups, 1, attrTypes, ParseGroupEntry, NULL, &reqFlags,
fLibinfoCache, keys );
}
else
{
outBuffer = GetRecordListLibInfo( fLocalNodeRef, name, kDSStdRecordTypeGroups, 1, attrTypes, ParseGroupEntry, NULL, &reqFlags,
fLibinfoCache, keys );
if( NULL == outBuffer )
{
outBuffer = GetRecordListLibInfo( fFlatFileNodeRef, name, kDSStdRecordTypeGroups, 1, attrTypes, ParseGroupEntry, NULL, &reqFlags,
fLibinfoCache, keys );
}
}
if( outBuffer != NULL )
{
uint32_t dcount = kvbuf_reset( outBuffer );
if( dcount != 1 )
{
kvbuf_free( outBuffer );
outBuffer = NULL;
}
}
if ( outBuffer == NULL && localOnlyPID == false ) {
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, NULL, CACHE_ENTRY_TYPE_GROUP | reqFlags, kNegativeCacheTime, "gr_name", name, NULL );
}
}
fStatsLock.WaitLock();
fCacheMissByFunction[kDSLUgetgrnam] += 1;
fStatsLock.SignalLock();
}
else
{
fStatsLock.WaitLock();
fCacheHitsByFunction[kDSLUgetgrnam] += 1;
fStatsLock.SignalLock();
DbgLog( kLogPlugin, "CCachePlugin::getgrnam - Cache hit for %s", name );
}
return( outBuffer );
}
kvbuf_t* CCachePlugin::DSgetgruuid ( kvbuf_t *inBuffer, pid_t inPID )
{
kvbuf_t *outBuffer = NULL;
tDataListPtr attrTypes = NULL;
uint32_t dictCount = kvbuf_reset( inBuffer );
uint32_t valCount = 0;
sCacheValidation *theValidation = NULL;
if( dictCount == 0 )
return NULL;
kvbuf_next_dict( inBuffer );
char *key = kvbuf_next_key( inBuffer, &valCount );
if( strcmp(key, "uuid") != 0 || valCount == 0 )
return NULL;
char *number = kvbuf_next_val( inBuffer );
if( number == NULL )
return NULL;
outBuffer = FetchFromCache( fLibinfoCache, 0, NULL, "gr_uuid", number, NULL );
if ( outBuffer == NULL )
{
attrTypes = dsBuildListFromStrings( fDirRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
kDS1AttrPassword,
kDS1AttrPrimaryGroupID,
kDS1AttrGeneratedUID,
kDSNAttrGroupMembership,
NULL );
if ( attrTypes != NULL )
{
bool localOnlyPID = IsLocalOnlyPID( inPID );
if( localOnlyPID == false )
{
outBuffer = ValueSearchLibInfo( fSearchNodeRef, kDS1AttrGeneratedUID, number, kDSStdRecordTypeGroups, 1, attrTypes, ParseGroupEntry,
NULL, NULL, &theValidation );
}
else
{
outBuffer = ValueSearchLibInfo( fLocalNodeRef, kDS1AttrGeneratedUID, number, kDSStdRecordTypeGroups, 1, attrTypes, ParseGroupEntry,
NULL, NULL, &theValidation );
if( NULL == outBuffer )
{
outBuffer = ValueSearchLibInfo( fFlatFileNodeRef, kDS1AttrGeneratedUID, number, kDSStdRecordTypeGroups, 1, attrTypes, ParseGroupEntry,
NULL, NULL, &theValidation );
}
}
if( outBuffer != NULL )
{
uint32_t dcount = kvbuf_reset( outBuffer );
const char *keys[] = { "gr_name", "gr_gid", "gr_uuid", NULL };
if ( dcount == 1 )
{
kvbuf_t *copy = kvbuf_init_zone( malloc_default_purgeable_zone(), outBuffer->databuf, outBuffer->datalen );
AddEntryToCacheWithKeys( fLibinfoCache, theValidation, copy, CACHE_ENTRY_TYPE_GROUP, kCacheTime, keys );
}
else
{
kvbuf_free( outBuffer );
outBuffer = NULL;
}
}
if ( outBuffer == NULL && localOnlyPID == false ) {
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, NULL, CACHE_ENTRY_TYPE_GROUP, kNegativeCacheTime, "gr_uuid", number, NULL );
}
dsDataListDeallocate( fDirRef, attrTypes );
DSFree( attrTypes );
}
fStatsLock.WaitLock();
fCacheMissByFunction[kDSLUgetgruuid] += 1;
fStatsLock.SignalLock();
}
else
{
fStatsLock.WaitLock();
fCacheHitsByFunction[kDSLUgetgruuid] += 1;
fStatsLock.SignalLock();
DbgLog( kLogPlugin, "CCachePlugin::getgruuid - Cache hit for %s", number );
}
DSRelease( theValidation );
return( outBuffer );
}
kvbuf_t* CCachePlugin::DSgetgrgid ( kvbuf_t *inBuffer, pid_t inPID )
{
kvbuf_t *outBuffer = NULL;
tDataListPtr attrTypes = NULL;
uint32_t dictCount = kvbuf_reset( inBuffer );
uint32_t valCount = 0;
sCacheValidation *theValidation = NULL;
if( dictCount == 0 )
return NULL;
kvbuf_next_dict( inBuffer );
char *key = kvbuf_next_key( inBuffer, &valCount );
if( strcmp(key, "gid") != 0 || valCount == 0 )
return NULL;
char *number = kvbuf_next_val( inBuffer );
if( number == NULL )
return NULL;
outBuffer = FetchFromCache( fLibinfoCache, 0, NULL, "gr_gid", number, NULL );
if ( outBuffer == NULL )
{
attrTypes = dsBuildListFromStrings( fDirRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
kDS1AttrPassword,
kDS1AttrPrimaryGroupID,
kDS1AttrGeneratedUID,
kDSNAttrGroupMembership,
NULL );
if ( attrTypes != NULL )
{
bool localOnlyPID = IsLocalOnlyPID( inPID );
if( localOnlyPID == false )
{
outBuffer = ValueSearchLibInfo( fSearchNodeRef, kDS1AttrPrimaryGroupID, number, kDSStdRecordTypeGroups, 1, attrTypes, ParseGroupEntry,
NULL, NULL, &theValidation );
}
else
{
outBuffer = ValueSearchLibInfo( fLocalNodeRef, kDS1AttrPrimaryGroupID, number, kDSStdRecordTypeGroups, 1, attrTypes, ParseGroupEntry,
NULL, NULL, &theValidation );
if( NULL == outBuffer )
{
outBuffer = ValueSearchLibInfo( fFlatFileNodeRef, kDS1AttrPrimaryGroupID, number, kDSStdRecordTypeGroups, 1, attrTypes, ParseGroupEntry,
NULL, NULL, &theValidation );
}
}
if( outBuffer != NULL )
{
uint32_t dcount = kvbuf_reset( outBuffer );
const char *keys[] = { "gr_name", "gr_gid", "gr_uuid", NULL };
if ( dcount == 1 )
{
kvbuf_t *copy = kvbuf_init_zone( malloc_default_purgeable_zone(), outBuffer->databuf, outBuffer->datalen );
AddEntryToCacheWithKeys( fLibinfoCache, theValidation, copy, CACHE_ENTRY_TYPE_GROUP, kCacheTime, keys );
}
else
{
kvbuf_free( outBuffer );
outBuffer = NULL;
}
}
if ( outBuffer == NULL && localOnlyPID == false ) {
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, NULL, CACHE_ENTRY_TYPE_GROUP, kNegativeCacheTime, "gr_gid", number, NULL );
}
dsDataListDeallocate( fDirRef, attrTypes );
DSFree( attrTypes );
}
fStatsLock.WaitLock();
fCacheMissByFunction[kDSLUgetgrgid] += 1;
fStatsLock.SignalLock();
}
else
{
fStatsLock.WaitLock();
fCacheHitsByFunction[kDSLUgetgrgid] += 1;
fStatsLock.SignalLock();
DbgLog( kLogPlugin, "CCachePlugin::getgrgid - Cache hit for %s", number );
}
DSRelease( theValidation );
return( outBuffer );
}
kvbuf_t* CCachePlugin::DSgetgrent( void )
{
kvbuf_t *outBuffer = NULL;
tDataListPtr attrTypes = NULL;
outBuffer = FetchFromCache( fLibinfoCache, 0, NULL, "grent", "1", NULL );
if ( outBuffer == NULL )
{
attrTypes = dsBuildListFromStrings( fDirRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
kDS1AttrPassword,
kDS1AttrPrimaryGroupID,
kDS1AttrGeneratedUID,
kDSNAttrGroupMembership,
NULL );
if ( attrTypes != NULL )
{
outBuffer = GetRecordListLibInfo( fSearchNodeRef, kDSRecordsAll, kDSStdRecordTypeGroups, 0, attrTypes, ParseGroupEntry, NULL, NULL,
NULL, NULL );
dsDataListDeallocate( fDirRef, attrTypes );
DSFree( attrTypes );
}
if ( outBuffer != NULL ) {
kvbuf_t *copy = kvbuf_init_zone( malloc_default_purgeable_zone(), outBuffer->databuf, outBuffer->datalen );
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, copy, CACHE_ENTRY_TYPE_GROUP, kEnumerationCacheTime, "grent", "1", NULL );
}
}
return( outBuffer );
}
kvbuf_t* CCachePlugin::DSgetfsbyname( kvbuf_t *inBuffer )
{
kvbuf_t *outBuffer = NULL;
tDataListPtr attrTypes = NULL;
uint32_t dictCount = kvbuf_reset( inBuffer );
uint32_t valCount = 0;
if( dictCount == 0 )
return NULL;
kvbuf_next_dict( inBuffer );
char *key = kvbuf_next_key( inBuffer, &valCount );
if( strcmp(key, "name") != 0 || valCount == 0 )
return NULL;
char *name = kvbuf_next_val( inBuffer );
if( name == NULL )
return NULL;
outBuffer = FetchFromCache( fLibinfoCache, 0, NULL, "fs_spec", name, NULL );
if ( outBuffer == NULL )
{
attrTypes = dsBuildListFromStrings( fDirRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
kDS1AttrVFSLinkDir,
kDS1AttrVFSType,
kDSNAttrVFSOpts,
kDS1AttrVFSDumpFreq,
kDS1AttrVFSPassNo,
NULL );
if ( attrTypes != NULL )
{
const char *keys[] = { "fs_spec", NULL };
outBuffer = GetRecordListLibInfo( fSearchNodeRef, name, kDSStdRecordTypeMounts, 1, attrTypes, ParseMountEntry, NULL, NULL,
fLibinfoCache, keys );
if( outBuffer != NULL )
{
uint32_t dcount = kvbuf_reset( outBuffer );
if ( dcount != 1 )
{
kvbuf_free( outBuffer );
outBuffer = NULL;
}
}
if ( outBuffer == NULL )
{
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, NULL, CACHE_ENTRY_TYPE_MOUNT, kNegativeCacheTime, "fs_spec", name, NULL );
}
dsDataListDeallocate( fDirRef, attrTypes );
DSFree( attrTypes );
}
fStatsLock.WaitLock();
fCacheMissByFunction[kDSLUgetfsbyname] += 1;
fStatsLock.SignalLock();
}
else
{
fStatsLock.WaitLock();
fCacheHitsByFunction[kDSLUgetfsbyname] += 1;
fStatsLock.SignalLock();
DbgLog( kLogPlugin, "CCachePlugin::getfsbyname - Cache hit for %s", name );
}
return( outBuffer );
}
kvbuf_t* CCachePlugin::DSgetfsent( pid_t inPID )
{
kvbuf_t *outBuffer = NULL;
tDataListPtr attrTypes = NULL;
outBuffer = FetchFromCache( fLibinfoCache, 0, NULL, "fsent", "1", NULL );
if ( outBuffer == NULL )
{
attrTypes = dsBuildListFromStrings( fDirRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
kDS1AttrVFSLinkDir,
kDS1AttrVFSType,
kDSNAttrVFSOpts,
kDS1AttrVFSDumpFreq,
kDS1AttrVFSPassNo,
NULL );
if ( attrTypes != NULL )
{
bool localOnlyPID = IsLocalOnlyPID( inPID );
if ( localOnlyPID == false )
{
outBuffer = GetRecordListLibInfo( fSearchNodeRef, kDSRecordsAll, kDSStdRecordTypeMounts, 0, attrTypes, ParseMountEntry, NULL, NULL,
NULL, NULL );
}
else
{
outBuffer = GetRecordListLibInfo( fLocalNodeRef, kDSRecordsAll, kDSStdRecordTypeMounts, 0, attrTypes, ParseMountEntry, outBuffer, NULL,
NULL, NULL );
outBuffer = GetRecordListLibInfo( fFlatFileNodeRef, kDSRecordsAll, kDSStdRecordTypeMounts, 0, attrTypes, ParseMountEntry, outBuffer, NULL,
NULL, NULL );
}
dsDataListDeallocate( fDirRef, attrTypes );
DSFree( attrTypes );
}
if ( outBuffer != NULL ) {
kvbuf_t *copy = kvbuf_init_zone( malloc_default_purgeable_zone(), outBuffer->databuf, outBuffer->datalen );
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, copy, CACHE_ENTRY_TYPE_MOUNT, kEnumerationCacheTime, "fsent", "1", NULL );
}
}
return( outBuffer );
}
kvbuf_t* CCachePlugin::DSgetaliasbyname( kvbuf_t *inBuffer )
{
kvbuf_t *outBuffer = NULL;
tDataListPtr attrTypes = NULL;
uint32_t dictCount = kvbuf_reset( inBuffer );
uint32_t valCount = 0;
if( dictCount == 0 )
return NULL;
kvbuf_next_dict( inBuffer );
char *key = kvbuf_next_key( inBuffer, &valCount );
if( strcmp(key, "name") != 0 || valCount == 0 )
return NULL;
char *name = kvbuf_next_val( inBuffer );
if( name == NULL )
return NULL;
outBuffer = FetchFromCache( fLibinfoCache, 0, NULL, "alias_name", name, NULL );
if ( outBuffer == NULL )
{
attrTypes = dsBuildListFromStrings( fDirRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
kDSNAttrMember,
"dsAttrTypeNative:members",
NULL );
if ( attrTypes != NULL )
{
const char *keys[] = {"alias_name",NULL};
outBuffer = GetRecordListLibInfo( fSearchNodeRef, name, kDSStdRecordTypeAliases, 1, attrTypes, ParseAliasEntry,
NULL, NULL, fLibinfoCache, keys );
if( outBuffer != NULL )
{
uint32_t dcount = kvbuf_reset( outBuffer );
if ( dcount != 1 )
{
kvbuf_free( outBuffer );
outBuffer = NULL;
}
}
if ( outBuffer == NULL )
{
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, NULL, CACHE_ENTRY_TYPE_ALIAS, kNegativeCacheTime, "alias_name", name, NULL );
}
dsDataListDeallocate( fDirRef, attrTypes );
DSFree( attrTypes );
}
fStatsLock.WaitLock();
fCacheMissByFunction[kDSLUalias_getbyname] += 1;
fStatsLock.SignalLock();
}
else
{
fStatsLock.WaitLock();
fCacheHitsByFunction[kDSLUalias_getbyname] += 1;
fStatsLock.SignalLock();
DbgLog( kLogPlugin, "CCachePlugin::getaliasbyname - Cache hit for %s", name );
}
return( outBuffer );
}
kvbuf_t* CCachePlugin::DSgetaliasent( void )
{
kvbuf_t *outBuffer = NULL;
tDataListPtr attrTypes = NULL;
outBuffer = FetchFromCache( fLibinfoCache, 0, NULL, "aliasent", "1", NULL );
if ( outBuffer == NULL )
{
attrTypes = dsBuildListFromStrings( fDirRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
kDSNAttrMember,
"dsAttrTypeNative:members",
NULL );
if ( attrTypes != NULL )
{
outBuffer = GetRecordListLibInfo( fSearchNodeRef, kDSRecordsAll, kDSStdRecordTypeAliases, 0, attrTypes, ParseAliasEntry,
NULL, NULL, NULL, NULL );
dsDataListDeallocate( fDirRef, attrTypes );
DSFree( attrTypes );
}
if ( outBuffer != NULL ) {
kvbuf_t *copy = kvbuf_init_zone( malloc_default_purgeable_zone(), outBuffer->databuf, outBuffer->datalen );
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, copy, CACHE_ENTRY_TYPE_ALIAS, kEnumerationCacheTime, "aliasent", "1", NULL );
}
}
return( outBuffer );
}
kvbuf_t* CCachePlugin::DSgetservbyname( kvbuf_t *inBuffer, pid_t inPID )
{
uint32_t dictCount = kvbuf_reset( inBuffer );
const char *service = NULL;
const char *proto = "";
if( dictCount != 0 )
{
char *key = NULL;
uint32_t count;
kvbuf_next_dict( inBuffer );
while( (key = kvbuf_next_key(inBuffer, &count)) )
{
if( strcmp(key, "name") == 0 )
service = kvbuf_next_val( inBuffer );
else if( strcmp(key, "proto") == 0 )
proto = kvbuf_next_val( inBuffer );
}
return DSgetservbyname_int( service, proto, inPID );
}
return NULL;
}
kvbuf_t* CCachePlugin::DSgetservbyname_int( const char *service, const char *proto, pid_t inPID )
{
kvbuf_t *outBuffer = NULL;
tDataListPtr attrTypes = NULL;
const char *pValues[] = { NULL, NULL }; sCacheValidation *theValidation = NULL;
if ( service != NULL && proto != NULL )
{
if (proto[0] == '\0')
outBuffer = FetchFromCache( fLibinfoCache, 0, NULL, "s_name", service, NULL );
else
outBuffer = FetchFromCache( fLibinfoCache, 0, NULL, "s_name", service, "s_proto", proto, NULL );
if ( outBuffer == NULL )
{
attrTypes = dsBuildListFromStrings( fDirRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
"dsAttrTypeNative:PortAndProtocol",
NULL );
if ( attrTypes != NULL )
{
pValues[1] = proto;
bool localOnlyPID = IsLocalOnlyPID( inPID );
if( localOnlyPID == false )
{
if ( proto[0] == '\0' )
{
outBuffer = ValueSearchLibInfo( fSearchNodeRef, kDSNAttrRecordName, service, kDSStdRecordTypeServices, 1, attrTypes, ParseServiceEntry,
NULL, NULL, &theValidation );
}
else
{
outBuffer = ValueSearchLibInfo( fSearchNodeRef, kDSNAttrRecordName, service, kDSStdRecordTypeServices, 0, attrTypes, ParseServiceEntry,
NULL, (void *)pValues, &theValidation );
}
}
else
{
if ( proto[0] == '\0' )
{
outBuffer = ValueSearchLibInfo( fLocalNodeRef, kDSNAttrRecordName, service, kDSStdRecordTypeServices, 1, attrTypes, ParseServiceEntry,
NULL, NULL, &theValidation );
}
else
{
outBuffer = ValueSearchLibInfo( fLocalNodeRef, kDSNAttrRecordName, service, kDSStdRecordTypeServices, 0, attrTypes, ParseServiceEntry,
NULL, (void *)pValues, &theValidation );
}
if( outBuffer == NULL )
{
if ( proto[0] == '\0' )
{
outBuffer = ValueSearchLibInfo( fFlatFileNodeRef, kDSNAttrRecordName, service, kDSStdRecordTypeServices, 1, attrTypes,
ParseServiceEntry, NULL, NULL, &theValidation );
}
else
{
outBuffer = ValueSearchLibInfo( fFlatFileNodeRef, kDSNAttrRecordName, service, kDSStdRecordTypeServices, 0, attrTypes,
ParseServiceEntry, NULL, (void *)pValues, &theValidation );
}
}
}
if( outBuffer != NULL )
{
const char *keyList1[] = { "s_name", "s_proto", NULL };
const char *keyList2[] = { "s_port", "s_proto", NULL };
const char *keyList3[] = { "s_name", NULL }; kvbuf_t *copy = kvbuf_init_zone( malloc_default_purgeable_zone(), outBuffer->databuf, outBuffer->datalen );
AddEntryToCacheWithKeylists( fLibinfoCache, theValidation, copy, CACHE_ENTRY_TYPE_SERVICE, kCacheTime, keyList1, keyList2,
(proto[0] == '\0' ? keyList3 : NULL), NULL );
}
if ( outBuffer == NULL && localOnlyPID == false ) {
if (proto[0] == '\0')
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, NULL, CACHE_ENTRY_TYPE_SERVICE, kNegativeCacheTime,
"s_name", service, NULL );
else
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, NULL, CACHE_ENTRY_TYPE_SERVICE, kNegativeCacheTime,
"s_name", service, "s_proto", proto, NULL );
}
dsDataListDeallocate( fDirRef, attrTypes );
DSFree( attrTypes );
}
fStatsLock.WaitLock();
fCacheMissByFunction[kDSLUgetservbyname] += 1;
fStatsLock.SignalLock();
}
else
{
fStatsLock.WaitLock();
fCacheHitsByFunction[kDSLUgetservbyname] += 1;
fStatsLock.SignalLock();
DbgLog( kLogPlugin, "CCachePlugin::getservbyname - Cache hit for %s:%s", service, proto );
}
}
DSRelease( theValidation );
return outBuffer;
}
kvbuf_t* CCachePlugin::DSgetservbyport( kvbuf_t *inBuffer, pid_t inPID )
{
uint32_t dictCount = kvbuf_reset( inBuffer );
char *port = NULL;
char *proto = NULL;
kvbuf_t *outBuffer = NULL;
tDataListPtr attrTypes = NULL;
sCacheValidation *theValidation = NULL;
if( dictCount != 0 )
{
char *key = NULL;
uint32_t count;
kvbuf_next_dict( inBuffer );
while( (key = kvbuf_next_key(inBuffer, &count)) )
{
if( strcmp(key, "port") == 0 )
port = kvbuf_next_val( inBuffer );
else if( strcmp(key, "proto") == 0 )
proto = kvbuf_next_val( inBuffer );
}
}
if( port != NULL && proto != NULL )
{
if (proto[0] == '\0')
outBuffer = FetchFromCache( fLibinfoCache, 0, NULL, "s_port", port, NULL );
else
outBuffer = FetchFromCache( fLibinfoCache, 0, NULL, "s_port", port, "s_proto", proto, NULL );
if ( outBuffer == NULL )
{
attrTypes = dsBuildListFromStrings( fDirRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
"dsAttrTypeNative:PortAndProtocol",
NULL );
if ( attrTypes != NULL )
{
char specificSearch[64] = { 0, };
if (proto[0] != '\0')
{
snprintf( specificSearch, sizeof(specificSearch), "%s/%s", port, proto );
}
bool localOnlyPID = IsLocalOnlyPID( inPID );
if( localOnlyPID == false )
{
if (specificSearch[0] != '\0')
{
outBuffer = ValueSearchLibInfo( fSearchNodeRef, "dsAttrTypeNative:PortAndProtocol", specificSearch, kDSStdRecordTypeServices, 0,
attrTypes, ParseServiceEntry, NULL, NULL, &theValidation );
}
else
{
outBuffer = ValueSearchLibInfo( fSearchNodeRef, kDS1AttrPort, port, kDSStdRecordTypeServices, 1, attrTypes, ParseServiceEntry,
NULL, NULL, &theValidation );
}
}
else
{
if (specificSearch[0] != '\0')
{
outBuffer = ValueSearchLibInfo( fLocalNodeRef, "dsAttrTypeNative:PortAndProtocol", specificSearch, kDSStdRecordTypeServices,
0, attrTypes, ParseServiceEntry, outBuffer, NULL, &theValidation );
}
else
{
outBuffer = ValueSearchLibInfo( fLocalNodeRef, kDS1AttrPort, port, kDSStdRecordTypeServices,
1, attrTypes, ParseServiceEntry, outBuffer, NULL, &theValidation );
}
if( outBuffer == NULL )
{
if (specificSearch[0] != '\0')
{
outBuffer = ValueSearchLibInfo( fFlatFileNodeRef, "dsAttrTypeNative:PortAndProtocol", specificSearch,
kDSStdRecordTypeServices, 0, attrTypes, ParseServiceEntry, outBuffer, NULL, &theValidation );
}
else
{
outBuffer = ValueSearchLibInfo( fFlatFileNodeRef, kDS1AttrPort, port, kDSStdRecordTypeServices,
1, attrTypes, ParseServiceEntry, outBuffer, NULL, &theValidation );
}
}
}
if( outBuffer != NULL )
{
const char *keyList1[] = { "s_name", "s_proto", NULL };
const char *keyList2[] = { "s_port", "s_proto", NULL };
const char *keyList3[] = { "s_port", NULL };
kvbuf_t *copy = kvbuf_init_zone( malloc_default_purgeable_zone(), outBuffer->databuf, outBuffer->datalen );
AddEntryToCacheWithKeylists( fLibinfoCache, theValidation, copy, CACHE_ENTRY_TYPE_SERVICE, kCacheTime, keyList1, keyList2,
(proto[0] == '\0' ? keyList3 : NULL), NULL );
}
if ( outBuffer == NULL && localOnlyPID == false ) {
if (proto[0] == '\0')
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, NULL, CACHE_ENTRY_TYPE_SERVICE, kNegativeCacheTime,
"s_port", port, NULL );
else
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, NULL, CACHE_ENTRY_TYPE_SERVICE, kNegativeCacheTime,
"s_port", port, "s_proto", proto, NULL );
}
dsDataListDeallocate( fDirRef, attrTypes );
DSFree( attrTypes );
}
fStatsLock.WaitLock();
fCacheMissByFunction[kDSLUgetservbyport] += 1;
fStatsLock.SignalLock();
}
else
{
fStatsLock.WaitLock();
fCacheHitsByFunction[kDSLUgetservbyport] += 1;
fStatsLock.SignalLock();
DbgLog( kLogPlugin, "CCachePlugin::getservbyport - Cache hit for %s:%s", port, proto );
}
}
DSRelease( theValidation );
return outBuffer;
}
kvbuf_t* CCachePlugin::DSgetservent( void )
{
kvbuf_t *outBuffer = NULL;
tDataListPtr attrTypes = NULL;
outBuffer = FetchFromCache( fLibinfoCache, 0, NULL, "servent", "1", NULL );
if ( outBuffer == NULL )
{
attrTypes = dsBuildListFromStrings( fDirRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
"dsAttrTypeNative:PortAndProtocol",
NULL );
if ( attrTypes != NULL )
{
outBuffer = GetRecordListLibInfo( fSearchNodeRef, kDSRecordsAll, kDSStdRecordTypeServices, 0, attrTypes, ParseServiceEntry,
NULL, NULL, NULL, NULL );
dsDataListDeallocate( fDirRef, attrTypes );
DSFree( attrTypes );
}
if ( outBuffer != NULL ) {
kvbuf_t *copy = kvbuf_init_zone( malloc_default_purgeable_zone(), outBuffer->databuf, outBuffer->datalen );
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, copy, CACHE_ENTRY_TYPE_SERVICE, kEnumerationCacheTime, "servent", "1", NULL );
}
}
return( outBuffer );
}
kvbuf_t* CCachePlugin::DSgetprotobyname( kvbuf_t *inBuffer, pid_t inPID )
{
kvbuf_t *outBuffer = NULL;
tDataListPtr attrTypes = NULL;
uint32_t dictCount = kvbuf_reset( inBuffer );
uint32_t valCount = 0;
if( dictCount == 0 )
return NULL;
kvbuf_next_dict( inBuffer );
char *key = kvbuf_next_key( inBuffer, &valCount );
if( strcmp(key, "name") != 0 || valCount == 0 )
return NULL;
char *name = kvbuf_next_val( inBuffer );
if( name == NULL )
return NULL;
outBuffer = FetchFromCache( fLibinfoCache, 0, NULL, "p_name", name, NULL );
if ( outBuffer == NULL )
{
attrTypes = dsBuildListFromStrings( fDirRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
"dsAttrTypeNative:number",
NULL );
if ( attrTypes != NULL )
{
const char *keys[] = { "p_name", "p_proto", NULL };
bool localOnlyPID = IsLocalOnlyPID( inPID );
if( localOnlyPID == false )
{
outBuffer = GetRecordListLibInfo( fSearchNodeRef, name, kDSStdRecordTypeProtocols, 1, attrTypes, ParseProtocolEntry, NULL, NULL,
fLibinfoCache, keys );
}
else
{
outBuffer = GetRecordListLibInfo( fLocalNodeRef, name, kDSStdRecordTypeProtocols, 1, attrTypes, ParseProtocolEntry, NULL, NULL,
fLibinfoCache, keys );
if( NULL == outBuffer )
{
outBuffer = GetRecordListLibInfo( fFlatFileNodeRef, name, kDSStdRecordTypeProtocols, 1, attrTypes, ParseProtocolEntry, NULL, NULL,
fLibinfoCache, keys );
}
}
if( outBuffer != NULL )
{
uint32_t dcount = kvbuf_reset( outBuffer );
if( dcount != 1 )
{
kvbuf_free( outBuffer );
outBuffer = NULL;
}
}
if ( outBuffer == NULL && localOnlyPID == false ) {
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, NULL, CACHE_ENTRY_TYPE_PROTOCOL, kNegativeCacheTime, "p_name", name, NULL );
}
dsDataListDeallocate( fDirRef, attrTypes );
DSFree( attrTypes );
}
fStatsLock.WaitLock();
fCacheMissByFunction[kDSLUgetprotobyname] += 1;
fStatsLock.SignalLock();
}
else
{
fStatsLock.WaitLock();
fCacheHitsByFunction[kDSLUgetprotobyname] += 1;
fStatsLock.SignalLock();
DbgLog( kLogPlugin, "CCachePlugin::getprotobyname - Cache hit for %s", name );
}
return( outBuffer );
}
kvbuf_t* CCachePlugin::DSgetprotobynumber( kvbuf_t *inBuffer, pid_t inPID )
{
kvbuf_t *outBuffer = NULL;
tDataListPtr attrTypes = NULL;
uint32_t dictCount = kvbuf_reset( inBuffer );
uint32_t valCount = 0;
sCacheValidation *theValidation = NULL;
if( dictCount == 0 )
return NULL;
kvbuf_next_dict( inBuffer );
char *key = kvbuf_next_key( inBuffer, &valCount );
if( strcmp(key, "number") != 0 || valCount == 0 )
return NULL;
char *number = kvbuf_next_val( inBuffer );
if( number == NULL )
return NULL;
outBuffer = FetchFromCache( fLibinfoCache, 0, NULL, "p_proto", number, NULL );
if ( outBuffer == NULL )
{
attrTypes = dsBuildListFromStrings( fDirRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
"dsAttrTypeNative:number",
NULL );
if ( attrTypes != NULL )
{
bool localOnlyPID = IsLocalOnlyPID( inPID );
if( localOnlyPID == false )
{
outBuffer = ValueSearchLibInfo( fSearchNodeRef, "dsAttrTypeNative:number", number, kDSStdRecordTypeProtocols, 1, attrTypes,
ParseProtocolEntry, NULL, NULL, &theValidation );
}
else
{
outBuffer = ValueSearchLibInfo( fLocalNodeRef, "dsAttrTypeNative:number", number, kDSStdRecordTypeProtocols, 1, attrTypes,
ParseProtocolEntry, NULL, NULL, &theValidation );
if( NULL == outBuffer )
{
outBuffer = ValueSearchLibInfo( fFlatFileNodeRef, "dsAttrTypeNative:number", number, kDSStdRecordTypeProtocols, 1, attrTypes, ParseProtocolEntry,
NULL, NULL, &theValidation );
}
}
if( outBuffer != NULL )
{
uint32_t dcount = kvbuf_reset( outBuffer );
const char *keys[] = { "p_name", "p_proto", NULL };
if( dcount == 1 )
{
kvbuf_t *copy = kvbuf_init_zone( malloc_default_purgeable_zone(), outBuffer->databuf, outBuffer->datalen );
AddEntryToCacheWithKeys( fLibinfoCache, theValidation, copy, CACHE_ENTRY_TYPE_PROTOCOL, kCacheTime, keys );
}
else
{
kvbuf_free( outBuffer );
outBuffer = NULL;
}
}
if ( outBuffer == NULL && localOnlyPID == false ) {
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, NULL, CACHE_ENTRY_TYPE_PROTOCOL, kNegativeCacheTime, "p_proto", number, NULL );
}
dsDataListDeallocate( fDirRef, attrTypes );
DSFree( attrTypes );
}
fStatsLock.WaitLock();
fCacheMissByFunction[kDSLUgetprotobynumber] += 1;
fStatsLock.SignalLock();
}
else
{
fStatsLock.WaitLock();
fCacheHitsByFunction[kDSLUgetprotobynumber] += 1;
fStatsLock.SignalLock();
DbgLog( kLogPlugin, "CCachePlugin::getprotobynumber - Cache hit for %s", number );
}
DSRelease( theValidation );
return( outBuffer );
}
kvbuf_t* CCachePlugin::DSgetprotoent( void )
{
kvbuf_t *outBuffer = NULL;
tDataListPtr attrTypes = NULL;
outBuffer = FetchFromCache( fLibinfoCache, 0, NULL, "protoent", "1", NULL );
if ( outBuffer == NULL )
{
attrTypes = dsBuildListFromStrings( fDirRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
"dsAttrTypeNative:number",
NULL );
if ( attrTypes != NULL )
{
outBuffer = GetRecordListLibInfo( fSearchNodeRef, kDSRecordsAll, kDSStdRecordTypeProtocols, 0, attrTypes, ParseProtocolEntry,
NULL, NULL, NULL, NULL );
dsDataListDeallocate( fDirRef, attrTypes );
DSFree( attrTypes );
}
if ( outBuffer != NULL ) {
kvbuf_t *copy = kvbuf_init_zone( malloc_default_purgeable_zone(), outBuffer->databuf, outBuffer->datalen );
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, copy, CACHE_ENTRY_TYPE_PROTOCOL, kEnumerationCacheTime, "protoent", "1", NULL );
}
}
return( outBuffer );
}
kvbuf_t* CCachePlugin::DSgetrpcbyname( kvbuf_t *inBuffer, pid_t inPID )
{
kvbuf_t *outBuffer = NULL;
tDataListPtr attrTypes = NULL;
uint32_t dictCount = kvbuf_reset( inBuffer );
uint32_t valCount = 0;
if( dictCount == 0 )
return NULL;
kvbuf_next_dict( inBuffer );
char *key = kvbuf_next_key( inBuffer, &valCount );
if( strcmp(key, "name") != 0 || valCount == 0 )
return NULL;
char *name = kvbuf_next_val( inBuffer );
if( name == NULL )
return NULL;
outBuffer = FetchFromCache( fLibinfoCache, 0, NULL, "r_name", name, NULL );
if ( outBuffer == NULL )
{
attrTypes = dsBuildListFromStrings( fDirRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
"dsAttrTypeNative:number",
NULL );
if ( attrTypes != NULL )
{
const char *keys[] = { "r_name", "r_number", NULL };
bool localOnlyPID = IsLocalOnlyPID( inPID );
if( localOnlyPID == false )
{
outBuffer = GetRecordListLibInfo( fSearchNodeRef, name, kDSStdRecordTypeRPC, 1, attrTypes, ParseRPCEntry, NULL, NULL,
fLibinfoCache, keys );
}
else
{
outBuffer = GetRecordListLibInfo( fLocalNodeRef, name, kDSStdRecordTypeRPC, 1, attrTypes, ParseRPCEntry, NULL, NULL,
fLibinfoCache, keys );
if( NULL == outBuffer )
{
outBuffer = GetRecordListLibInfo( fFlatFileNodeRef, name, kDSStdRecordTypeRPC, 1, attrTypes, ParseRPCEntry, NULL, NULL,
fLibinfoCache, keys );
}
}
if( outBuffer != NULL )
{
uint32_t dcount = kvbuf_reset( outBuffer );
if( dcount != 1 )
{
kvbuf_free( outBuffer );
outBuffer = NULL;
}
}
if ( outBuffer == NULL && localOnlyPID == false ) {
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, NULL, CACHE_ENTRY_TYPE_RPC, kNegativeCacheTime, "r_name", name, NULL );
}
dsDataListDeallocate( fDirRef, attrTypes );
DSFree( attrTypes );
}
fStatsLock.WaitLock();
fCacheMissByFunction[kDSLUgetrpcbyname] += 1;
fStatsLock.SignalLock();
}
else
{
fStatsLock.WaitLock();
fCacheHitsByFunction[kDSLUgetrpcbyname] += 1;
fStatsLock.SignalLock();
DbgLog( kLogPlugin, "CCachePlugin::getrpcbyname - Cache hit for %s", name );
}
return( outBuffer );
}
kvbuf_t* CCachePlugin::DSgetrpcbynumber( kvbuf_t *inBuffer, pid_t inPID )
{
kvbuf_t *outBuffer = NULL;
tDataListPtr attrTypes = NULL;
uint32_t dictCount = kvbuf_reset( inBuffer );
uint32_t valCount = 0;
sCacheValidation *theValidation = NULL;
if( dictCount == 0 )
return NULL;
kvbuf_next_dict( inBuffer );
char *key = kvbuf_next_key( inBuffer, &valCount );
if( strcmp(key, "number") != 0 || valCount == 0 )
return NULL;
char *number = kvbuf_next_val( inBuffer );
if( number == NULL )
return NULL;
outBuffer = FetchFromCache( fLibinfoCache, 0, NULL, "r_number", number, NULL );
if ( outBuffer == NULL )
{
attrTypes = dsBuildListFromStrings( fDirRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
"dsAttrTypeNative:number",
NULL );
if ( attrTypes != NULL )
{
bool localOnlyPID = IsLocalOnlyPID( inPID );
if( localOnlyPID == false )
{
outBuffer = ValueSearchLibInfo( fSearchNodeRef, "dsAttrTypeNative:number", number, kDSStdRecordTypeRPC, 1, attrTypes, ParseRPCEntry,
NULL, NULL, &theValidation );
}
else
{
outBuffer = ValueSearchLibInfo( fLocalNodeRef, "dsAttrTypeNative:number", number, kDSStdRecordTypeRPC, 1, attrTypes, ParseRPCEntry,
NULL, NULL, &theValidation );
if( NULL == outBuffer )
{
outBuffer = ValueSearchLibInfo( fFlatFileNodeRef, "dsAttrTypeNative:number", number, kDSStdRecordTypeRPC, 1, attrTypes, ParseRPCEntry,
NULL, NULL, &theValidation );
}
}
if( outBuffer != NULL )
{
uint32_t dcount = kvbuf_reset( outBuffer );
const char *keys[] = { "r_name", "r_number", NULL };
if( dcount == 1 )
{
kvbuf_t *copy = kvbuf_init_zone( malloc_default_purgeable_zone(), outBuffer->databuf, outBuffer->datalen );
AddEntryToCacheWithKeys( fLibinfoCache, theValidation, copy, CACHE_ENTRY_TYPE_RPC, kCacheTime, keys );
}
else
{
kvbuf_free( outBuffer );
outBuffer = NULL;
}
}
if ( outBuffer == NULL && localOnlyPID == false ) {
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, NULL, CACHE_ENTRY_TYPE_RPC, kNegativeCacheTime, "r_number", number, NULL );
}
dsDataListDeallocate( fDirRef, attrTypes );
DSFree( attrTypes );
}
fStatsLock.WaitLock();
fCacheMissByFunction[kDSLUgetrpcbynumber] += 1;
fStatsLock.SignalLock();
}
else
{
fStatsLock.WaitLock();
fCacheHitsByFunction[kDSLUgetrpcbynumber] += 1;
fStatsLock.SignalLock();
DbgLog( kLogPlugin, "CCachePlugin::getrpcbynumber - Cache hit for %s", number );
}
DSRelease( theValidation );
return( outBuffer );
}
kvbuf_t* CCachePlugin::DSgetrpcent( void )
{
kvbuf_t *outBuffer = NULL;
tDataListPtr attrTypes = NULL;
outBuffer = FetchFromCache( fLibinfoCache, 0, NULL, "rpcent", "1", NULL );
if ( outBuffer == NULL )
{
attrTypes = dsBuildListFromStrings( fDirRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
"dsAttrTypeNative:number",
NULL );
if ( attrTypes != NULL )
{
outBuffer = GetRecordListLibInfo( fSearchNodeRef, kDSRecordsAll, kDSStdRecordTypeRPC, 0, attrTypes, ParseRPCEntry, NULL, NULL,
NULL, NULL );
dsDataListDeallocate( fDirRef, attrTypes );
DSFree( attrTypes );
}
if ( outBuffer != NULL ) {
kvbuf_t *copy = kvbuf_init_zone( malloc_default_purgeable_zone(), outBuffer->databuf, outBuffer->datalen );
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, copy, CACHE_ENTRY_TYPE_RPC, kEnumerationCacheTime, "rpcent", "1", NULL );
}
}
return( outBuffer );
}
kvbuf_t* CCachePlugin::DSgetnetbyname( kvbuf_t *inBuffer, pid_t inPID )
{
kvbuf_t *outBuffer = NULL;
tDataListPtr attrTypes = NULL;
uint32_t dictCount = kvbuf_reset( inBuffer );
uint32_t valCount = 0;
if( dictCount == 0 )
return NULL;
kvbuf_next_dict( inBuffer );
char *key = kvbuf_next_key( inBuffer, &valCount );
if( strcmp(key, "name") != 0 || valCount == 0 )
return NULL;
char *name = kvbuf_next_val( inBuffer );
if( name == NULL )
return NULL;
outBuffer = FetchFromCache( fLibinfoCache, 0, NULL, "n_name", name, NULL );
if ( outBuffer == NULL )
{
outBuffer = FetchFromCache( fLibinfoCache, 0, NULL, "n_aliases", name, NULL );
}
if ( outBuffer == NULL )
{
attrTypes = dsBuildListFromStrings( fDirRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
"dsAttrTypeNative:address",
NULL );
if ( attrTypes != NULL )
{
const char *keys[] = { "n_name", "n_aliases", "n_net", NULL };
bool localOnlyPID = IsLocalOnlyPID( inPID );
if( localOnlyPID == false )
{
outBuffer = GetRecordListLibInfo( fSearchNodeRef, name, kDSStdRecordTypeNetworks, 1, attrTypes, ParseNetworkEntry, NULL, NULL,
fLibinfoCache, keys );
}
else
{
outBuffer = GetRecordListLibInfo( fLocalNodeRef, name, kDSStdRecordTypeNetworks, 1, attrTypes, ParseNetworkEntry, NULL, NULL,
fLibinfoCache, keys );
if( NULL == outBuffer )
{
outBuffer = GetRecordListLibInfo( fFlatFileNodeRef, name, kDSStdRecordTypeNetworks, 1, attrTypes, ParseNetworkEntry, NULL, NULL,
fLibinfoCache, keys );
}
}
if( outBuffer != NULL )
{
uint32_t dcount = kvbuf_reset( outBuffer );
if( dcount != 1 )
{
kvbuf_free( outBuffer );
outBuffer = NULL;
}
}
if ( outBuffer == NULL && localOnlyPID == false ) {
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, NULL, CACHE_ENTRY_TYPE_NETWORK, kNegativeCacheTime, "n_name", name, NULL );
}
dsDataListDeallocate( fDirRef, attrTypes );
DSFree( attrTypes );
}
fStatsLock.WaitLock();
fCacheMissByFunction[kDSLUgetnetbyname] += 1;
fStatsLock.SignalLock();
}
else
{
fStatsLock.WaitLock();
fCacheHitsByFunction[kDSLUgetnetbyname] += 1;
fStatsLock.SignalLock();
DbgLog( kLogPlugin, "CCachePlugin::getnetbyname - Cache hit for %s", name );
}
return( outBuffer );
}
kvbuf_t* CCachePlugin::DSgetnetbyaddr( kvbuf_t *inBuffer, pid_t inPID )
{
kvbuf_t *outBuffer = NULL;
tDataListPtr attrTypes = NULL;
uint32_t dictCount = kvbuf_reset( inBuffer );
char *number = NULL;
sCacheValidation *theValidation = NULL;
if( dictCount == 0 )
return NULL;
if( dictCount != 0 )
{
char *key = NULL;
uint32_t count;
kvbuf_next_dict( inBuffer );
while( (key = kvbuf_next_key(inBuffer, &count)) )
{
if( strcmp(key, "net") == 0 )
number = kvbuf_next_val( inBuffer );
}
}
outBuffer = FetchFromCache( fLibinfoCache, 0, NULL, "n_net", number, NULL );
if ( outBuffer == NULL )
{
attrTypes = dsBuildListFromStrings( fDirRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
"dsAttrTypeNative:address",
NULL );
if ( attrTypes != NULL )
{
bool localOnlyPID = IsLocalOnlyPID( inPID );
if( localOnlyPID == false )
{
outBuffer = ValueSearchLibInfo( fSearchNodeRef, "dsAttrTypeNative:address", number, kDSStdRecordTypeNetworks, 1, attrTypes,
ParseNetworkEntry, NULL, NULL, &theValidation );
}
else
{
outBuffer = ValueSearchLibInfo( fLocalNodeRef, "dsAttrTypeNative:address", number, kDSStdRecordTypeNetworks, 1, attrTypes,
ParseNetworkEntry, NULL, NULL, &theValidation );
if( NULL == outBuffer )
{
outBuffer = ValueSearchLibInfo( fFlatFileNodeRef, "dsAttrTypeNative:address", number, kDSStdRecordTypeNetworks, 1, attrTypes,
ParseNetworkEntry, NULL, NULL, &theValidation );
}
}
if( outBuffer != NULL )
{
uint32_t dcount = kvbuf_reset( outBuffer );
const char *keys[] = { "n_name", "n_aliases", "n_net", NULL };
if( dcount == 1 )
{
kvbuf_t *copy = kvbuf_init_zone( malloc_default_purgeable_zone(), outBuffer->databuf, outBuffer->datalen );
AddEntryToCacheWithKeys( fLibinfoCache, theValidation, copy, CACHE_ENTRY_TYPE_NETWORK, kCacheTime, keys );
}
else
{
kvbuf_free( outBuffer );
outBuffer = NULL;
}
}
if ( outBuffer == NULL && localOnlyPID == false ) {
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, NULL, CACHE_ENTRY_TYPE_NETWORK, kNegativeCacheTime, "n_net", number, NULL );
}
dsDataListDeallocate( fDirRef, attrTypes );
DSFree( attrTypes );
}
fStatsLock.WaitLock();
fCacheMissByFunction[kDSLUgetnetbyaddr] += 1;
fStatsLock.SignalLock();
}
else
{
fStatsLock.WaitLock();
fCacheHitsByFunction[kDSLUgetnetbyaddr] += 1;
fStatsLock.SignalLock();
DbgLog( kLogPlugin, "CCachePlugin::getnetbyaddr - Cache hit for %s", number );
}
DSRelease( theValidation );
return( outBuffer );
}
kvbuf_t* CCachePlugin::DSgetnetent( void )
{
kvbuf_t *outBuffer = NULL;
tDataListPtr attrTypes = NULL;
outBuffer = FetchFromCache( fLibinfoCache, 0, NULL, "netent", "1", NULL );
if ( outBuffer == NULL )
{
attrTypes = dsBuildListFromStrings( fDirRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
"dsAttrTypeNative:address",
NULL );
if ( attrTypes != NULL )
{
outBuffer = GetRecordListLibInfo( fSearchNodeRef, kDSRecordsAll, kDSStdRecordTypeNetworks, 0, attrTypes, ParseNetworkEntry,
NULL, NULL, NULL, NULL );
dsDataListDeallocate( fDirRef, attrTypes );
DSFree( attrTypes );
}
if ( outBuffer != NULL ) {
kvbuf_t *copy = kvbuf_init_zone( malloc_default_purgeable_zone(), outBuffer->databuf, outBuffer->datalen );
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, copy, CACHE_ENTRY_TYPE_NETWORK, kEnumerationCacheTime, "netent", "1", NULL );
}
}
return( outBuffer );
}
kvbuf_t* CCachePlugin::DSgetnetgrent( kvbuf_t *inBuffer )
{
kvbuf_t *outBuffer = NULL;
tDataListPtr attrTypes = NULL;
uint32_t dictCount = kvbuf_reset( inBuffer );
uint32_t valCount = 0;
char *name = NULL;
char *key = NULL;
if( dictCount == 0 )
return NULL;
kvbuf_next_dict( inBuffer );
while( (key = kvbuf_next_key(inBuffer, &valCount)) )
{
if( strcmp(key, "netgroup") == 0 )
name = kvbuf_next_val( inBuffer );
}
if( name == NULL )
return NULL;
outBuffer = FetchFromCache( fLibinfoCache, 0, NULL, "netgroup", name, NULL );
if ( outBuffer == NULL )
{
attrTypes = dsBuildListFromStrings( fDirRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
kDSNAttrNetGroups,
"dsAttrTypeNative:triplet",
NULL );
if ( attrTypes != NULL )
{
outBuffer = GetRecordListLibInfo( fSearchNodeRef, name, kDSStdRecordTypeNetGroups, 1, attrTypes, ParseNetGroupEntry, NULL, NULL,
NULL, NULL );
if ( outBuffer == NULL )
{
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, NULL, CACHE_ENTRY_TYPE_GROUP, kNegativeCacheTime, "netgroup", name, NULL );
}
dsDataListDeallocate( fDirRef, attrTypes );
DSFree( attrTypes );
}
}
else
{
DbgLog( kLogPlugin, "CCachePlugin::getnetgrent - Cache hit for %s", name );
}
return( outBuffer );
}
kvbuf_t *CCachePlugin::DSinnetgr( kvbuf_t *inBuffer )
{
kvbuf_t *tempBuffer = NULL;
tDataListPtr attrTypes = NULL;
uint32_t dictCount = kvbuf_reset( inBuffer );
uint32_t valCount = 0;
char *key = NULL;
char *name = NULL;
const char *triplet[3] = { "", "", "" };
if( dictCount == 0 )
return NULL;
kvbuf_next_dict( inBuffer );
while( (key = kvbuf_next_key(inBuffer, &valCount)) )
{
if( strcmp(key, "netgroup") == 0 )
name = kvbuf_next_val( inBuffer );
else if( strcmp(key, "host") == 0 )
triplet[0] = kvbuf_next_val( inBuffer );
else if( strcmp(key, "user") == 0 )
triplet[1] = kvbuf_next_val( inBuffer );
else if( strcmp(key, "domain") == 0 )
triplet[2] = kvbuf_next_val( inBuffer );
}
if( name == NULL )
return NULL;
tempBuffer = FetchFromCache( fLibinfoCache, 0, NULL, "netgroup", name, "host", triplet[0], "user", triplet[1], "domain", triplet[2], NULL );
if ( tempBuffer == NULL )
{
attrTypes = dsBuildListFromStrings( fDirRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
"dsAttrTypeNative:triplet",
NULL );
if ( attrTypes != NULL )
{
tempBuffer = GetRecordListLibInfo( fSearchNodeRef, name, kDSStdRecordTypeNetGroups, 1, attrTypes, ParseNetGroupEntry, NULL, triplet,
fLibinfoCache, NULL );
if ( tempBuffer == NULL )
{
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, NULL, CACHE_ENTRY_TYPE_GROUP, kCacheTime, "netgroup", name, "host", triplet[0],
"user", triplet[1], "domain", triplet[2], NULL );
}
dsDataListDeallocate( fDirRef, attrTypes );
DSFree( attrTypes );
}
fStatsLock.WaitLock();
fCacheMissByFunction[kDSLUinnetgr] += 1;
fStatsLock.SignalLock();
}
else
{
fStatsLock.WaitLock();
fCacheHitsByFunction[kDSLUinnetgr] += 1;
fStatsLock.SignalLock();
DbgLog( kLogPlugin, "CCachePlugin::innetgr - Cache hit for %s - %s, %s, %s", name, (triplet[0] ? triplet[0] : ""),
(triplet[1] ? triplet[1] : ""), (triplet[2] ? triplet[2] : ""));
}
kvbuf_t *outBuffer = kvbuf_new();
kvbuf_add_dict( outBuffer );
kvbuf_add_key( outBuffer, "result" );
kvbuf_add_val( outBuffer, (kvbuf_reset(tempBuffer) > 0 ? "1" : "0") );
kvbuf_free( tempBuffer );
return outBuffer;
}
#ifdef HANDLE_DNS_LOOKUPS
void CCachePlugin::InitiateDNSQuery( sDNSLookup *inLookup, bool inParallel )
{
if ( inParallel && inLookup->fTotal > 1 )
{
DbgLog( kLogDebug, "CCachePlugin::InitiateDNSQuery - Called with Total = %d", inLookup->fTotal );
IssueParallelDNSQueries( inLookup );
}
else
{
if ( inParallel )
DbgLog( kLogDebug, "CCachePlugin::InitiateDNSQuery - AI_PARALLEL was requested, but only one query" );
for (int index = 0; index < inLookup->fTotal; index++ )
{
sDNSQuery query;
query.fLookupEntry = inLookup;
query.fQueryIndex = index;
inLookup->fOutstanding = 1;
DoDNSQuery( &query );
}
}
}
static void __IssueParallelDNSQueries( sDNSLookup *inLookup )
{
bool reissueQueries;
do
{
int iSlot = AddToDNSThreads();
reissueQueries = false; inLookup->fOutstanding = 0;
bzero( inLookup->fQueryFinished, sizeof(inLookup->fQueryFinished) );
void (^theblock)(size_t) = ^(size_t jobindex) {
sDNSQuery query;
query.fLookupEntry = inLookup;
query.fQueryIndex = (int32_t) jobindex;
DbgLog( kLogDebug, "CCachePlugin::IssueParallelDNSQueries - Issuing query for index %d", jobindex );
__sync_add_and_fetch( &(inLookup->fOutstanding), 1 );
DoDNSQuery( &query );
DbgLog( kLogDebug, "CCachePlugin::IssueParallelDNSQueries - Complete query for index %d", jobindex );
if ( inLookup->fQueryTypes[jobindex] == ns_t_a && inLookup->fAnswers[jobindex] != NULL )
{
uint64_t timeout;
if ( inLookup->fAnswerTime[jobindex] > 1000.0 ) {
timeout = (uint64_t) inLookup->fAnswerTime[jobindex] * (uint64_t) inLookup->fTotal * (uint64_t) NSEC_PER_USEC;
}
else if ( inLookup->fQueryTypes[jobindex] == ns_t_a ) {
timeout = 500000000ull;
}
if ( inLookup->fTimerSource == NULL ) {
void (^source_cancel)(dispatch_source_t) = ^(dispatch_source_t ds) {
long err_code = 0;
long err_domain = dispatch_source_get_error( ds, &err_code );
switch ( err_domain )
{
case DISPATCH_ERROR_DOMAIN_NO_ERROR:
break;
case DISPATCH_ERROR_DOMAIN_POSIX:
if ( err_code == ECANCELED ) {
return;
}
default:
DbgLog( kLogError, "CCache::IssueParallelDNSQueries - dispatch timer receved error domain %L error %L",
(long) err_domain, (long) err_code );
}
DbgLog( kLogDebug, "CCachePlugin::IssueParallelDNSQueries - timer has fired" );
int rc = pthread_mutex_lock( &gActiveThreadMutex );
assert( rc == 0 );
int numThreadsCancelled = 0;
for ( int index = 0; index < inLookup->fTotal; index++ )
{
for ( int slot = 0; slot < gActiveThreadCount; slot++ )
{
if ( inLookup->fThreadID[index] != NULL && gActiveThreads[slot] == inLookup->fThreadID[index] )
{
if ( gNotifyTokens[slot] == 0 )
{
char notify_name[128];
int notify_token = 0;
snprintf( notify_name, sizeof(notify_name), "self.thread.%lu", (unsigned long) gActiveThreads[slot] );
int status = notify_register_plain( notify_name, ¬ify_token );
if (status == NOTIFY_STATUS_OK)
{
notify_set_state( notify_token, ThreadStateExitRequested );
gNotifyTokens[slot] = notify_token;
gThreadAbandon[slot] = true;
DbgLog( kLogDebug, "CCachePlugin::AbandonDNSQueries called for index %d slot %d notification '%s' token %X",
index, slot, notify_name, gInterruptTokens[slot] );
res_interrupt_request( gInterruptTokens[slot] );
++numThreadsCancelled;
}
}
else
{
DbgLog( kLogDebug, "CCachePlugin::AbandonDNSQueries index %d already being cancelled, just setting abandon flag",
index );
gThreadAbandon[slot] = true;
}
break;
}
}
}
DbgLog( kLogInfo, "CCachePlugin::AbandonDNSQueries cancellation of %d threads requested", numThreadsCancelled );
rc = pthread_mutex_unlock( &gActiveThreadMutex );
assert( rc == 0 );
};
inLookup->fSemaphore = dispatch_semaphore_create( 0 );
assert( inLookup->fSemaphore != NULL );
DbgLog( kLogInfo, "CCachePlugin::IssueParallelDNSQueries scheduled cancellation timer for %L ms", (long) (timeout / 1000000ull) );
dispatch_source_attr_t attr = dispatch_source_attr_create();
dispatch_source_attr_set_finalizer( attr,
^(dispatch_source_t ds) {
dispatch_semaphore_signal( inLookup->fSemaphore );
} );
inLookup->fTimerSource = dispatch_source_timer_create( DISPATCH_TIMER_ONESHOT,
timeout,
0,
attr,
dispatch_get_concurrent_queue(DISPATCH_QUEUE_PRIORITY_HIGH),
source_cancel );
dispatch_release( attr );
assert( inLookup->fTimerSource != NULL );
}
}
};
dispatch_apply( inLookup->fTotal, dispatch_get_concurrent_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT), theblock );
if ( inLookup->fSemaphore != NULL ) {
DbgLog( kLogDebug, "CCachePlugin::IssueParallelDNSQueries - cancelling timer source for %X", inLookup );
dispatch_cancel( inLookup->fTimerSource );
dispatch_release( inLookup->fTimerSource );
inLookup->fTimerSource = NULL;
dispatch_semaphore_wait( inLookup->fSemaphore, DISPATCH_TIME_FOREVER );
dispatch_release( inLookup->fSemaphore );
inLookup->fSemaphore = NULL;
}
if ( RemoveFromDNSThreads(iSlot) == true )
{
DbgLog( kLogDebug, "CCachePlugin::IssueParallelDNSQueries - re-issuing queries due to DNS change" );
for ( int ii = 0; ii < inLookup->fTotal; ii++ )
{
if ( inLookup->fAnswers[ii] != NULL ) {
dns_free_reply( inLookup->fAnswers[ii] );
inLookup->fAnswers[ii] = NULL;
}
inLookup->fQueryFinished[ii] = false;
inLookup->fAnswerTime[ii] = 0.0;
}
reissueQueries = true;
}
} while ( reissueQueries );
}
void CCachePlugin::IssueParallelDNSQueries( sDNSLookup *inLookup )
{
__IssueParallelDNSQueries( inLookup ); }
#endif
kvbuf_t* CCachePlugin::DSgethostbyname( kvbuf_t *inBuffer, pid_t inPID, bool inParallelQuery, sDNSLookup *inLookup )
{
uint32_t dictCount = kvbuf_reset( inBuffer );
uint32_t valCount = 0;
const char *pIPv4 = "0";
const char *pIPv6 = "0";
char *key;
char *name = NULL;
if( dictCount == 0 )
return NULL;
kvbuf_next_dict( inBuffer );
while( (key = kvbuf_next_key(inBuffer, &valCount)) )
{
if( strcmp(key, "name") == 0 )
{
name = kvbuf_next_val( inBuffer );
}
else if( strcmp(key, "ipv4") == 0 )
{
pIPv4 = kvbuf_next_val( inBuffer );
}
else if( strcmp(key, "ipv6") == 0 )
{
pIPv6 = kvbuf_next_val( inBuffer );
}
}
return DSgethostbyname_int( name, pIPv4, pIPv6, inPID, inParallelQuery, inLookup );
}
kvbuf_t* CCachePlugin::DSgethostbyname_int( char *inName, const char *inIPv4, const char *inIPv6, int inPID, bool inParallelQuery, sDNSLookup *inLookup,
int32_t *outTTL )
{
uint32_t ipv4 = 0;
uint32_t ipv6 = 0;
__block kvbuf_t *outBuffer = NULL;
tDataListPtr attrTypes = NULL;
int32_t ttl = kDefaultTTLValue;
__block sCacheValidation *theValidation = NULL;
if( NULL != inIPv4 )
{
ipv4 = strtol( inIPv4, NULL, 10 );
}
if( NULL != inIPv6 )
{
ipv6 = strtol( inIPv6, NULL, 10 );
}
if( NULL == inName || (0 == ipv4 && 0 == ipv6) )
return NULL;
if( ipv4 != 0 )
{
outBuffer = FetchFromCache( fLibinfoCache, 0, &ttl, "h_name", inName, "ipv4", inIPv4, (ipv6 ? "ipv6" : NULL), inIPv6, NULL );
if( outBuffer == NULL )
{
outBuffer = FetchFromCache( fLibinfoCache, 0, &ttl, "h_aliases", inName, "ipv4", inIPv4, (ipv6 ? "ipv6" : NULL), inIPv6, NULL );
}
}
else
{
outBuffer = FetchFromCache( fLibinfoCache, 0, &ttl, "h_name", inName, "ipv6", inIPv6, NULL );
if( outBuffer == NULL )
{
outBuffer = FetchFromCache( fLibinfoCache, 0, &ttl, "h_aliases", inName, "ipv6", inIPv6, NULL );
}
}
if( outBuffer == NULL )
{
attrTypes = dsBuildListFromStrings( fDirRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
(1 == ipv4 ? kDSNAttrIPAddress : (1 == ipv6 ? kDSNAttrIPv6Address : NULL)),
((1 == ipv4 && 1 == ipv6) ? kDSNAttrIPv6Address : NULL),
NULL );
if ( attrTypes != NULL )
{
#ifdef ALLOW_NETWORK_HOST_SEARCHES
bool localOnlyPID = IsLocalOnlyPID( inPID );
if( localOnlyPID == false )
{
outBuffer = GetRecordListLibInfo( fSearchNodeRef, inName, kDSStdRecordTypeHosts, 1, attrTypes, ParseHostEntry, NULL, NULL,
NULL, NULL, &theValidation );
}
else
#else
{
outBuffer = GetRecordListLibInfo( fLocalNodeRef, inName, kDSStdRecordTypeHosts, 1, attrTypes, ParseHostEntry, NULL, NULL,
NULL, NULL, &theValidation );
if( NULL == outBuffer )
{
outBuffer = GetRecordListLibInfo( fFlatFileNodeRef, inName, kDSStdRecordTypeHosts, 1, attrTypes, ParseHostEntry, NULL, NULL,
NULL, NULL, &theValidation );
}
bool localOnlyPID = IsLocalOnlyPID( inPID );
if ( localOnlyPID == false )
{
dispatch_sync( fNISQueue,
^(void) {
if ( NULL == outBuffer && fNISNodeRef != 0 ) {
outBuffer = GetRecordListLibInfo( fNISNodeRef, inName, kDSStdRecordTypeHosts, 1, attrTypes, ParseHostEntry, NULL, NULL,
NULL, NULL, &theValidation );
}
} );
}
}
#endif
#ifdef HANDLE_DNS_LOOKUPS
if( NULL == outBuffer )
{
sDNSLookup *pAnswer = inLookup;
char *actualName = NULL;
char *domainMatch = NULL; uint16_t aliasCount = 0;
bool ipv4Found = false;
bool ipv6Found = false;
char *aliases[1024];
ttl = kDefaultTTLValue;
if( pAnswer == NULL )
{
pAnswer = new sDNSLookup;
}
if( 0 != ipv6 )
{
pAnswer->AddQuery( fClassIN, fTypeAAAA, inName );
}
if( 0 != ipv4 )
{
pAnswer->AddQuery( fClassIN, fTypeA, inName );
}
InitiateDNSQuery( pAnswer, inParallelQuery );
outBuffer = kvbuf_new();
kvbuf_add_dict( outBuffer );
int nameLen = strlen( inName );
if( pAnswer->fTotal > 1 && inName[nameLen-1] != '.' )
{
int iMatch[pAnswer->fTotal];
int iLowest = 255;
int iDomainIndex = 0;
char *pDomain = NULL;
for( int ii = 0; ii < pAnswer->fTotal; ii++ )
{
iMatch[ii] = 255;
}
if( _res.options & RES_INIT == 0 )
{
res_init();
}
while( (pDomain = _res.dnsrch[iDomainIndex]) != NULL )
{
int newLen = nameLen + 1 + strlen(pDomain) + 1;
char *pTemp = (char *) calloc( newLen, sizeof(char) );
snprintf( pTemp, newLen, "%s.%s", inName, pDomain );
DbgLog( kLogPlugin, "CCachePlugin::gethostbyname - checking name as FQDN %s", pTemp );
for( int zz = 0; zz < pAnswer->fTotal; zz++ )
{
dns_reply_t *reply = pAnswer->fAnswers[zz];
if( NULL != reply )
{
if( (reply->header != NULL) && (reply->header->ancount > 0) )
{
int index = 0;
while( index < reply->header->ancount && iMatch[zz] != 255 )
{
if( NULL != reply->answer[index] )
{
uint16_t iType = reply->answer[index]->dnstype;
if( iType == fTypeA || iType == fTypeAAAA || iType == fTypeCNAME )
{
if( strcmp(reply->answer[index]->name, pTemp) == 0 )
{
iMatch[zz] = iDomainIndex;
if( iDomainIndex < iLowest )
iLowest = iDomainIndex;
}
}
}
index++;
}
}
}
}
iDomainIndex++;
DSFree( pTemp );
}
if( iDomainIndex == 0 )
{
DbgLog( kLogPlugin, "CCachePlugin::gethostbyname - search domains = %d", iDomainIndex );
}
if( iLowest < 255 )
{
for( int zz = 0; zz < pAnswer->fTotal; zz++ )
{
if( pAnswer->fAnswers[zz] != NULL )
{
if( iMatch[zz] > iLowest )
{
dns_reply_t *reply = pAnswer->fAnswers[zz];
if( reply->header->ancount > 0 && reply->answer[0] != NULL )
{
DbgLog( kLogPlugin, "CCachePlugin::gethostbyname - disposing of answer %s", reply->answer[0]->name );
}
dns_free_reply( pAnswer->fAnswers[zz] );
pAnswer->fAnswers[zz] = NULL;
}
else if( domainMatch == NULL )
{
domainMatch = strdup( _res.dnsrch[iDomainIndex] );
DbgLog( kLogPlugin, "CCachePlugin::gethostbyname - answer is in search domain %s", _res.dnsrch[iDomainIndex] );
}
}
}
}
}
else
{
DbgLog( kLogDebug, "CCachePlugin::gethostbyname - only one query so skipping domain check" );
}
for( int zz = 0; zz < pAnswer->fTotal; zz++ )
{
dns_reply_t *reply = pAnswer->fAnswers[zz];
if( NULL != reply )
{
if( (reply->header != NULL) && (reply->header->ancount > 0) )
{
int index = 0;
if( fTypeA == pAnswer->fQueryTypes[zz] )
{
kvbuf_add_key( outBuffer, "h_ipv4_addr_list" );
ipv4Found = true;
}
else if( fTypeAAAA == pAnswer->fQueryTypes[zz] )
{
kvbuf_add_key( outBuffer, "h_ipv6_addr_list" );
ipv6Found = true;
}
else
{
continue;
}
int iface = 0;
if (reply->server->sa_family == AF_INET)
{
memcpy( &iface, (((struct sockaddr_in *)(reply->server))->sin_zero), 4 );
}
else if (reply->server->sa_family == AF_INET6)
{
iface = ((struct sockaddr_in6 *)(reply->server))->sin6_scope_id;
}
while( index < reply->header->ancount )
{
if( NULL != reply->answer[index] )
{
int32_t tempTTL = reply->answer[index]->ttl;
if( reply->answer[index]->dnstype == fTypeA )
{
dns_address_record_t *address = reply->answer[index]->data.A;
if( NULL == actualName )
{
actualName = reply->answer[index]->name;
}
if( NULL != address )
{
kvbuf_add_val( outBuffer, inet_ntoa(address->addr) );
}
SetMaxTTL( ttl, tempTTL );
}
else if( reply->answer[index]->dnstype == fTypeAAAA )
{
dns_in6_address_record_t *address = reply->answer[index]->data.AAAA;
char buffer[ INET6_ADDRSTRLEN ];
if( NULL == actualName )
{
actualName = reply->answer[index]->name;
}
if( NULL != address )
{
char tempBuffer[INET6_ADDRSTRLEN + 16];
char ifname[IF_NAMESIZE];
inet_ntop( AF_INET6, &(address->addr), buffer, INET6_ADDRSTRLEN );
if( if_indextoname(iface, ifname) != NULL )
{
snprintf( tempBuffer, sizeof(tempBuffer), "%s%%%s", buffer, ifname );
kvbuf_add_val( outBuffer, tempBuffer );
}
else
{
kvbuf_add_val( outBuffer, buffer );
}
}
SetMaxTTL( ttl, tempTTL );
}
else if( reply->answer[index]->dnstype == fTypeCNAME )
{
char *newAlias = reply->answer[index]->name;
for( int ii = 0; ii < aliasCount; ii++ )
{
if( strcmp(aliases[ii], newAlias) == 0 )
{
newAlias = NULL;
break;
}
}
if( NULL != newAlias )
{
aliases[aliasCount] = newAlias;
aliasCount++;
}
}
}
index++;
}
}
}
else if ( pAnswer->fMinimumTTL[zz] > 0 );
{
SetMaxTTL( ttl, pAnswer->fMinimumTTL[zz] );
}
}
if( NULL != outBuffer )
{
if( actualName != NULL )
{
kvbuf_add_key( outBuffer, "h_name" );
kvbuf_add_val( outBuffer, actualName );
kvbuf_add_key( outBuffer, "ipv4" );
kvbuf_add_val( outBuffer, inIPv4 );
kvbuf_add_key( outBuffer, "ipv6" );
kvbuf_add_val( outBuffer, inIPv6 );
if( domainMatch != NULL )
{
kvbuf_add_key( outBuffer, "searchDomainUsed" );
kvbuf_add_val( outBuffer, domainMatch );
}
char *pAliasName = (actualName != NULL && strcmp(inName, actualName) == 0 ? NULL : inName);
if( aliasCount > 0 )
{
kvbuf_add_key( outBuffer, "h_aliases" );
for( int ii = 0; ii < aliasCount; ii++ )
{
kvbuf_add_val( outBuffer, aliases[ii] );
if( NULL != pAliasName && strcmp(aliases[ii], pAliasName) == 0 )
{
pAliasName = NULL;
}
}
if( NULL != pAliasName )
{
kvbuf_add_val( outBuffer, pAliasName );
}
}
else if( NULL != pAliasName )
{
kvbuf_add_key( outBuffer, "h_aliases" );
kvbuf_add_val( outBuffer, pAliasName );
}
}
else
{
kvbuf_free( outBuffer );
outBuffer = NULL;
}
}
if( inLookup == NULL )
{
DSDelete( pAnswer );
}
}
else
#endif
{
kvbuf_add_key( outBuffer, "ipv4" );
kvbuf_add_val( outBuffer, inIPv4 );
kvbuf_add_key( outBuffer, "ipv6" );
kvbuf_add_val( outBuffer, inIPv6 );
}
#ifdef CACHE_HOST_ENTRIES
if ( outBuffer != NULL )
#else
if ( outBuffer != NULL && theValidation != NULL )
#endif
{
kvbuf_t *copy = kvbuf_init_zone( malloc_default_purgeable_zone(), outBuffer->databuf, outBuffer->datalen );
if( ipv4 == 1 && ipv6 == 1 )
{
const char *keylist1[] = { "h_name", "ipv4", NULL };
const char *keylist2[] = { "h_name", "ipv6", NULL };
const char *keylist3[] = { "h_name", "ipv4", "ipv6", NULL };
const char *keylist4[] = { "h_aliases", "ipv4", NULL };
const char *keylist5[] = { "h_aliases", "ipv6", NULL };
const char *keylist6[] = { "h_aliases", "ipv4", "ipv6", NULL };
fLibinfoCache->fCacheLock.WaitLock();
RemoveEntryWithMultiKey( fLibinfoCache, "h_name", inName, "ipv4", "1", "ipv6", "1", NULL );
RemoveEntryWithMultiKey( fLibinfoCache, "h_name", inName, "ipv4", "1", NULL );
RemoveEntryWithMultiKey( fLibinfoCache, "h_name", inName, "ipv6", "1", NULL );
AddEntryToCacheWithKeylists( fLibinfoCache, theValidation, copy, CACHE_ENTRY_TYPE_HOST | CACHE_ENTRY_TYPE_REPLACE, ttl,
keylist1, keylist2, keylist3, keylist4, keylist5, keylist6, NULL );
fLibinfoCache->fCacheLock.SignalLock();
}
else if( ipv4 == 1 )
{
const char *keylist1[] = { "h_name", "ipv4", NULL };
const char *keylist2[] = { "h_aliases", "ipv4", NULL };
fLibinfoCache->fCacheLock.WaitLock();
RemoveEntryWithMultiKey( fLibinfoCache, "h_name", inName, "ipv4", "1", NULL );
AddEntryToCacheWithKeylists( fLibinfoCache, theValidation, copy, CACHE_ENTRY_TYPE_HOST | CACHE_ENTRY_TYPE_REPLACE, ttl,
keylist1, keylist2, NULL );
fLibinfoCache->fCacheLock.SignalLock();
}
else
{
const char *keylist1[] = { "h_name", "ipv6", NULL };
const char *keylist2[] = { "h_aliases", "ipv6", NULL };
fLibinfoCache->fCacheLock.WaitLock();
RemoveEntryWithMultiKey( fLibinfoCache, "h_name", inName, "ipv6", "1", NULL );
AddEntryToCacheWithKeylists( fLibinfoCache, theValidation, copy, CACHE_ENTRY_TYPE_HOST | CACHE_ENTRY_TYPE_REPLACE, ttl,
keylist1, keylist2, NULL );
fLibinfoCache->fCacheLock.SignalLock();
}
if( outTTL != NULL )
(*outTTL) = ttl;
}
#ifdef CACHE_HOST_ENTRIES
else if ( localOnlyPID == false )
{
if ( ttl > 0 )
{
fLibinfoCache->fCacheLock.WaitLock();
if ( ipv4 != 0 )
{
outBuffer = FetchFromCache( fLibinfoCache, 0, &ttl, "h_name", inName, "ipv4", inIPv4, (ipv6 ? "ipv6" : NULL), inIPv6, NULL );
if ( outBuffer == NULL )
outBuffer = FetchFromCache( fLibinfoCache, 0, &ttl, "h_aliases", inName, "ipv4", inIPv4, (ipv6 ? "ipv6" : NULL), inIPv6, NULL );
}
else
{
outBuffer = FetchFromCache( fLibinfoCache, 0, &ttl, "h_name", inName, "ipv6", inIPv6, NULL );
if ( outBuffer == NULL )
outBuffer = FetchFromCache( fLibinfoCache, 0, &ttl, "h_aliases", inName, "ipv6", inIPv6, NULL );
}
if ( outBuffer == NULL )
{
outBuffer = kvbuf_new();
if ( ipv4 == 1 && ipv6 == 1 )
{
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, NULL, CACHE_ENTRY_TYPE_HOST, ttl, "h_name", inName,
"ipv4", "1", "ipv6", "1", NULL );
}
else if ( ipv4 == 1 )
{
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, NULL, CACHE_ENTRY_TYPE_HOST, ttl, "h_name", inName,
"ipv4", "1", NULL );
}
else
{
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, NULL, CACHE_ENTRY_TYPE_HOST, ttl, "h_name", inName,
"ipv6", "1", NULL );
}
}
fLibinfoCache->fCacheLock.SignalLock();
}
else
{
DbgLog( kLogDebug, "CCachePlugin::gethostbyname - query for %s didn't return A/AAAA records - no cache entries created", inName );
}
}
#endif
dsDataListDeallocate( fDirRef, attrTypes );
DSFree( attrTypes );
}
fStatsLock.WaitLock();
fCacheMissByFunction[kDSLUgethostbyname] += 1;
fStatsLock.SignalLock();
}
else
{
fStatsLock.WaitLock();
fCacheHitsByFunction[kDSLUgethostbyname] += 1;
fStatsLock.SignalLock();
DbgLog( kLogPlugin, "CCachePlugin::gethostbyname - Cache hit for %s", inName );
#ifdef HANDLE_DNS_LOOKUPS
if( inLookup != NULL )
{
DbgLog( kLogDebug, "CCachePlugin::gethostbyname - have a query to initiate" );
InitiateDNSQuery( inLookup, inParallelQuery );
}
#endif
}
DSRelease( theValidation );
return( outBuffer );
}
kvbuf_t* CCachePlugin::DSgethostbyname_service( kvbuf_t *inBuffer, pid_t inPID )
{
uint32_t dictCount = kvbuf_reset( inBuffer );
uint32_t valCount = 0;
const char *pIPv4 = "0";
const char *pIPv6 = "0";
const char *service = NULL;
const char *proto = "";
char *key;
char *name = NULL;
if( dictCount == 0 )
return NULL;
kvbuf_next_dict( inBuffer );
while ( (key = kvbuf_next_key(inBuffer, &valCount)) != NULL )
{
if ( strcmp(key, "name") == 0 ) {
name = kvbuf_next_val( inBuffer );
}
else if ( strcmp(key, "ipv4") == 0 ) {
pIPv4 = kvbuf_next_val( inBuffer );
}
else if ( strcmp(key, "ipv6") == 0 ) {
pIPv6 = kvbuf_next_val( inBuffer );
}
else if ( strcmp(key, "s_name") == 0 ) {
service = kvbuf_next_val( inBuffer );
}
else if ( strcmp(key, "s_proto") == 0 ) {
proto = kvbuf_next_val( inBuffer );
}
}
kvbuf_t *hostLookup = DSgethostbyname_int( name, pIPv4, pIPv6, inPID, true, NULL );
if ( service != NULL ) {
kvbuf_t *serviceLookup = DSgetservbyname_int( service, proto, inPID );
if ( serviceLookup != NULL ) {
if ( hostLookup != NULL ) {
kvbuf_append_kvbuf( hostLookup, serviceLookup );
kvbuf_free( serviceLookup );
}
else {
hostLookup = serviceLookup;
}
}
}
return hostLookup;
}
kvbuf_t* CCachePlugin::DSgethostbyaddr( kvbuf_t *inBuffer, pid_t inPID )
{
__block kvbuf_t *outBuffer = NULL;
tDataListPtr attrTypes = NULL;
uint32_t dictCount = kvbuf_reset( inBuffer );
int32_t ttl = kDefaultTTLValue;
uint32_t valCount = 0;
char *address = NULL;
uint32_t family = 0;
__block sCacheValidation *theValidation = NULL;
char *key;
if( dictCount == 0 )
return NULL;
kvbuf_next_dict( inBuffer );
while( (key = kvbuf_next_key(inBuffer, &valCount)) )
{
if( strcmp(key, "address") == 0 )
{
address = kvbuf_next_val( inBuffer );
}
else if( strcmp(key, "family") == 0 )
{
char *pTemp = kvbuf_next_val( inBuffer );
if( NULL != pTemp )
{
family = strtol( pTemp, NULL, 10 );
}
}
}
if( family == 0 || address == NULL )
return NULL;
outBuffer = FetchFromCache( fLibinfoCache, 0, NULL, (family == AF_INET ? "h_ipv4_addr_list" : "h_ipv6_addr_list"), address, NULL );
if( NULL == outBuffer )
{
const char *addressAttribute = (AF_INET == family ? kDSNAttrIPAddress : kDSNAttrIPv6Address);
attrTypes = dsBuildListFromStrings( fDirRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
addressAttribute,
NULL );
if ( attrTypes != NULL )
{
bool localOnlyPID = IsLocalOnlyPID( inPID );
if( NULL == outBuffer )
{
#ifdef ALLOW_NETWORK_HOST_SEARCHES
if( localOnlyPID == false )
{
outBuffer = ValueSearchLibInfo( fSearchNodeRef, addressAttribute, address, kDSStdRecordTypeHosts, 1, attrTypes, ParseHostEntry,
NULL, NULL, &theValidation );
}
else
#else
{
outBuffer = ValueSearchLibInfo( fLocalNodeRef, addressAttribute, address, kDSStdRecordTypeHosts, 1, attrTypes,
ParseHostEntry, NULL, NULL, &theValidation );
if( NULL == outBuffer )
{
outBuffer = ValueSearchLibInfo( fFlatFileNodeRef, addressAttribute, address, kDSStdRecordTypeHosts, 1, attrTypes,
ParseHostEntry, NULL, NULL, &theValidation );
}
if( localOnlyPID == false )
{
dispatch_sync( fNISQueue,
^(void) {
if ( NULL == outBuffer && fNISNodeRef != 0 ) {
outBuffer = ValueSearchLibInfo( fNISNodeRef, addressAttribute, address, kDSStdRecordTypeHosts, 1, attrTypes,
ParseHostEntry, NULL, NULL, &theValidation );
}
} );
}
}
#endif
#ifdef HANDLE_DNS_LOOKUPS
if( NULL == outBuffer )
{
dns_handle_t dns = dns_open( NULL );
dns_reply_t *reply = NULL;
if( dns )
{
unsigned char buffer[ 16 ];
int slot = AddToDNSThreads();
if( inet_pton(family, address, buffer) == 1 )
{
char query[256];
if( AF_INET == family )
{
snprintf( query, sizeof(query), "%d.%d.%d.%d.in-addr.arpa",
(int) buffer[3], (int) buffer[2], (int) buffer[1], (int) buffer[0] );
}
else if( AF_INET6 == family )
{
snprintf( query, sizeof(query),
"%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.ip6.arpa",
buffer[15]&0xf, buffer[15] >> 4, buffer[14]&0xf, buffer[14] >> 4,
buffer[13]&0xf, buffer[13] >> 4, buffer[12]&0xf, buffer[12] >> 4,
buffer[11]&0xf, buffer[11] >> 4, buffer[10]&0xf, buffer[10] >> 4,
buffer[9]&0xf, buffer[9] >> 4, buffer[8]&0xf, buffer[8] >> 4,
buffer[7]&0xf, buffer[7] >> 4, buffer[6]&0xf, buffer[6] >> 4,
buffer[5]&0xf, buffer[5] >> 4, buffer[4]&0xf, buffer[4] >> 4,
buffer[3]&0xf, buffer[3] >> 4, buffer[2]&0xf, buffer[2] >> 4,
buffer[1]&0xf, buffer[1] >> 4, buffer[0]&0xf, buffer[0] >> 4 );
}
reply = idna_dns_lookup( dns, query, fClassIN, fTypePTR, &ttl );
}
dns_free( dns );
RemoveFromDNSThreads( slot );
}
if( NULL != reply )
{
if ( (reply->header != NULL) && (DNS_STATUS_OK == reply->status) )
{
for ( int ii = 0; ii < reply->header->ancount; ii++ )
{
if ( (NULL != reply->answer[ii]) && (ns_t_ptr == reply->answer[ii]->dnstype) )
{
dns_domain_name_record_t *PTR = reply->answer[ii]->data.PTR;
SetMaxTTL( ttl, reply->answer[ii]->ttl );
if( NULL != PTR && PTR->name != NULL )
{
outBuffer = kvbuf_new();
kvbuf_add_dict( outBuffer );
kvbuf_add_key( outBuffer, "h_name" );
kvbuf_add_val( outBuffer, PTR->name );
kvbuf_add_key( outBuffer, (family == AF_INET ? "h_ipv4_addr_list" : "h_ipv6_addr_list") );
kvbuf_add_val( outBuffer, address );
break;
}
}
}
}
else if ( reply->authority[0] != NULL )
{
SetMaxTTL( ttl, reply->authority[0]->data.SOA->minimum );
}
dns_free_reply( reply );
}
}
#endif
#ifdef CACHE_HOST_ENTRIES
if ( outBuffer != NULL )
#else
if ( outBuffer != NULL && theValidation != NULL )
#endif
{
uint32_t dcount = kvbuf_reset( outBuffer );
if( dcount == 1 )
{
kvbuf_t *copy = kvbuf_init_zone( malloc_default_purgeable_zone(), outBuffer->databuf, outBuffer->datalen );
AddEntryToCacheWithMultiKey( fLibinfoCache, theValidation, copy, CACHE_ENTRY_TYPE_HOST, ttl,
(family == AF_INET ? "h_ipv4_addr_list" : "h_ipv6_addr_list"), address, NULL );
}
else
{
kvbuf_free( outBuffer );
outBuffer = NULL;
}
}
}
if ( outBuffer == NULL && ttl > 0 && localOnlyPID == false )
{
AddEntryToCacheWithMultiKey( fLibinfoCache, theValidation, NULL, CACHE_ENTRY_TYPE_HOST, ttl,
(family == AF_INET ? "h_ipv4_addr_list" : "h_ipv6_addr_list"), address, NULL );
outBuffer = kvbuf_new();
}
dsDataListDeallocate( fDirRef, attrTypes );
DSFree( attrTypes );
}
fStatsLock.WaitLock();
fCacheMissByFunction[kDSLUgethostbyaddr] += 1;
fStatsLock.SignalLock();
}
else
{
fStatsLock.WaitLock();
fCacheHitsByFunction[kDSLUgethostbyaddr] += 1;
fStatsLock.SignalLock();
DbgLog( kLogPlugin, "CCachePlugin::gethostbyaddr - Cache hit for %s", address );
}
DSRelease( theValidation );
return( outBuffer );
}
kvbuf_t* CCachePlugin::DSgethostent( kvbuf_t *inBuffer, pid_t inPID )
{
__block kvbuf_t *outBuffer = NULL;
if( outBuffer == NULL )
{
tDataListPtr attrTypes = dsBuildListFromStrings( fDirRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
kDSNAttrIPAddress,
kDSNAttrIPv6Address,
NULL );
if( attrTypes != NULL )
{
#ifdef ALLOW_NETWORK_HOST_SEARCHES
bool localOnlyPID = IsLocalOnlyPID( inPID );
if( localOnlyPID == false )
{
outBuffer = GetRecordListLibInfo( fSearchNodeRef, kDSRecordsAll, kDSStdRecordTypeHosts, 0, attrTypes, ParseHostEntry, NULL, NULL,
NULL, NULL );
}
else
#else
{
outBuffer = GetRecordListLibInfo( fFlatFileNodeRef, kDSRecordsAll, kDSStdRecordTypeHosts, 0, attrTypes, ParseHostEntry, outBuffer, NULL,
NULL, NULL );
outBuffer = GetRecordListLibInfo( fLocalNodeRef, kDSRecordsAll, kDSStdRecordTypeHosts, 0, attrTypes, ParseHostEntry, outBuffer, NULL,
NULL, NULL );
bool localOnlyPID = IsLocalOnlyPID( inPID );
if( localOnlyPID == false )
{
dispatch_sync( fNISQueue,
^(void) {
if ( fNISNodeRef != 0 ) {
outBuffer = GetRecordListLibInfo( fNISNodeRef, kDSRecordsAll, kDSStdRecordTypeHosts, 0, attrTypes, ParseHostEntry, outBuffer, NULL,
NULL, NULL );
}
} );
}
}
dsDataListDeallocate( fDirRef, attrTypes );
DSFree( attrTypes );
}
#endif
fStatsLock.WaitLock();
fCacheMissByFunction[kDSLUgethostent] += 1;
fStatsLock.SignalLock();
}
return( outBuffer );
}
#ifdef HANDLE_DNS_LOOKUPS
kvbuf_t* CCachePlugin::DSgetnameinfo( kvbuf_t *inBuffer, pid_t inPID )
{
kvbuf_t *outBuffer = NULL;
kvbuf_t *tempBuffer = NULL;
tDataListPtr attrTypes = NULL;
uint32_t dictCount = kvbuf_reset( inBuffer );
int32_t ttl = kDefaultTTLValue;
uint32_t valCount = 0;
char *reqAddress = NULL;
uint32_t family = 0;
char *pFamily = NULL;
uint16_t port = 0;
const char *pPort = "0";
uint32_t flags = 0;
char pCacheFlags[16] = { 0, };
char *key;
char canonicalAddr[INET6_ADDRSTRLEN];
if( dictCount == 0 )
return NULL;
kvbuf_next_dict( inBuffer );
while( (key = kvbuf_next_key(inBuffer, &valCount)) )
{
if( strcmp(key, "address") == 0 )
{
reqAddress = kvbuf_next_val( inBuffer );
}
else if( strcmp(key, "family") == 0 )
{
pFamily = kvbuf_next_val( inBuffer );
if( NULL != pFamily )
{
family = strtol( pFamily, NULL, 10 );
}
}
else if( strcmp(key, "port") == 0 )
{
pPort = kvbuf_next_val( inBuffer );
if( NULL != pPort )
{
port = strtol( pPort, NULL, 10 );
}
else
{
pPort = "0";
}
}
else if( strcmp(key, "flags") == 0 )
{
char *pTemp = kvbuf_next_val( inBuffer );
if( NULL != pTemp )
{
flags = strtoul( pTemp, NULL, 10 );
}
}
}
uint32_t workingFlags = flags ^ (flags & NI_NOFQDN);
snprintf( pCacheFlags, sizeof(pCacheFlags), "%u", workingFlags );
if ( reqAddress != NULL )
{
uint32_t tempFamily = AF_UNSPEC;
char canonicalBuffer[16];
if( inet_pton(AF_INET6, reqAddress, canonicalBuffer) == 1 )
tempFamily = AF_INET6;
else if( inet_pton(AF_INET, reqAddress, canonicalBuffer) == 1 )
tempFamily = AF_INET;
if ( tempFamily == AF_UNSPEC )
return NULL;
if ( inet_ntop(tempFamily, canonicalBuffer, canonicalAddr, sizeof(canonicalAddr)) == NULL )
return NULL;
}
tempBuffer = FetchFromCache( fLibinfoCache, 0, NULL, "gni_address", canonicalAddr, "gni_family", pFamily, "gni_port", pPort, "flags", pCacheFlags, NULL );
if( NULL == tempBuffer )
{
const char *addressAttribute = (AF_INET == family ? kDSNAttrIPAddress : kDSNAttrIPv6Address);
attrTypes = dsBuildListFromStrings( fDirRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
addressAttribute,
NULL );
if ( attrTypes != NULL )
{
bool localOnlyPID = IsLocalOnlyPID( inPID );
#ifndef CACHE_HOST_ENTRIES
bool fromOD = false;
#endif
if( NULL == tempBuffer )
{
if( NULL != reqAddress && (0 == (flags & NI_NUMERICHOST) || NI_NAMEREQD == (flags & NI_NAMEREQD)) &&
(AF_INET == family || AF_INET6 == family) )
{
__block kvbuf_t *searchBuffer = NULL;
#ifdef ALLOW_NETWORK_HOST_SEARCHES
if( localOnlyPID == false )
{
searchBuffer = ValueSearchLibInfo( fSearchNodeRef, addressAttribute, canonicalAddr, kDSStdRecordTypeHosts, 1, attrTypes,
ParseHostEntry, NULL, NULL, NULL );
}
else
#else
{
searchBuffer = ValueSearchLibInfo( fLocalNodeRef, addressAttribute, canonicalAddr, kDSStdRecordTypeHosts, 1, attrTypes,
ParseHostEntry, NULL, NULL, NULL );
if( NULL == searchBuffer )
{
searchBuffer = ValueSearchLibInfo( fFlatFileNodeRef, addressAttribute, canonicalAddr, kDSStdRecordTypeHosts, 1, attrTypes,
ParseHostEntry, NULL, NULL, NULL );
}
if( localOnlyPID == false )
{
dispatch_sync( fNISQueue,
^(void) {
if ( NULL == outBuffer && fNISNodeRef != 0 ) {
searchBuffer = ValueSearchLibInfo( fNISNodeRef, addressAttribute, canonicalAddr, kDSStdRecordTypeHosts, 1, attrTypes,
ParseHostEntry, NULL, NULL, NULL );
}
} );
}
}
#endif
if( kvbuf_reset(searchBuffer) > 0 )
{
tempBuffer = kvbuf_new();
kvbuf_add_dict( tempBuffer );
kvbuf_next_dict( searchBuffer );
while( (key = kvbuf_next_key(searchBuffer, &valCount)) )
{
if( strcmp(key, "h_name") == 0 )
{
char *pHostName = kvbuf_next_val( searchBuffer );
if( NULL != pHostName )
{
kvbuf_add_key( tempBuffer, "gni_name" );
kvbuf_add_val( tempBuffer, pHostName );
}
break;
}
}
#ifndef CACHE_HOST_ENTRIES
fromOD = true;
#endif
}
kvbuf_free( searchBuffer );
if( NULL == tempBuffer )
{
dns_handle_t dns = dns_open( NULL );
dns_reply_t *reply = NULL;
if( dns )
{
unsigned char buffer[ 16 ];
int slot = AddToDNSThreads();
if( inet_pton(family, canonicalAddr, buffer) == 1 )
{
char query[256];
if( AF_INET == family )
{
snprintf( query, sizeof(query), "%d.%d.%d.%d.in-addr.arpa",
(int) buffer[3], (int) buffer[2], (int) buffer[1], (int) buffer[0] );
}
else if( AF_INET6 == family )
{
snprintf( query, sizeof(query),
"%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.ip6.arpa",
buffer[15]&0xf, buffer[15] >> 4, buffer[14]&0xf, buffer[14] >> 4,
buffer[13]&0xf, buffer[13] >> 4, buffer[12]&0xf, buffer[12] >> 4,
buffer[11]&0xf, buffer[11] >> 4, buffer[10]&0xf, buffer[10] >> 4,
buffer[9]&0xf, buffer[9] >> 4, buffer[8]&0xf, buffer[8] >> 4,
buffer[7]&0xf, buffer[7] >> 4, buffer[6]&0xf, buffer[6] >> 4,
buffer[5]&0xf, buffer[5] >> 4, buffer[4]&0xf, buffer[4] >> 4,
buffer[3]&0xf, buffer[3] >> 4, buffer[2]&0xf, buffer[2] >> 4,
buffer[1]&0xf, buffer[1] >> 4, buffer[0]&0xf, buffer[0] >> 4 );
}
reply = idna_dns_lookup( dns, query, fClassIN, fTypePTR, &ttl );
}
dns_free( dns );
RemoveFromDNSThreads( slot );
}
if ( (NULL != reply) && (DNS_STATUS_OK == reply->status) && (reply->header != NULL) )
{
for ( int ii = 0; ii < reply->header->ancount; ii++ )
{
if ( (NULL != reply->answer[ii]) && (ns_t_ptr == reply->answer[ii]->dnstype) )
{
dns_domain_name_record_t *PTR = reply->answer[ii]->data.PTR;
SetMaxTTL( ttl, reply->answer[ii]->ttl );
if ( NULL != PTR && PTR->name != NULL )
{
tempBuffer = kvbuf_new();
kvbuf_add_dict( tempBuffer );
kvbuf_add_key( tempBuffer, "gni_name" );
kvbuf_add_val( tempBuffer, PTR->name );
break;
}
}
}
dns_free_reply( reply );
}
}
}
if( NULL != pPort && (0 == (flags & NI_NAMEREQD) || tempBuffer != NULL) )
{
if( 0 == (flags & NI_NUMERICSERV) )
{
kvbuf_t *request = kvbuf_new();
kvbuf_add_dict( request );
kvbuf_add_key( request, "port" );
kvbuf_add_val( request, pPort );
if( (flags & NI_DGRAM) == NI_DGRAM )
{
kvbuf_add_key( request, "proto" );
kvbuf_add_val( request, "udp" );
}
else
{
kvbuf_add_key( request, "proto" );
kvbuf_add_val( request, "tcp" );
}
kvbuf_t *answer = DSgetservbyport( request, inPID );
if( kvbuf_reset(answer) > 0 )
{
if( NULL == tempBuffer )
{
tempBuffer = kvbuf_new();
kvbuf_add_dict( tempBuffer );
}
kvbuf_next_dict( answer );
while( (key = kvbuf_next_key(answer, &valCount)) )
{
if( strcmp(key, "s_name") == 0 )
{
char *pService = kvbuf_next_val( answer );
if( NULL != pService )
{
kvbuf_add_key( tempBuffer, "gni_service" );
kvbuf_add_val( tempBuffer, pService );
}
}
}
}
else
{
kvbuf_add_key( tempBuffer, "gni_service" );
kvbuf_add_val( tempBuffer, pPort );
}
kvbuf_free( answer );
kvbuf_free( request );
}
}
#ifdef CACHE_HOST_ENTRIES
if( tempBuffer != NULL )
#else
if( tempBuffer != NULL && fromOD == true )
#endif
{
uint32_t dcount = kvbuf_reset( tempBuffer );
if( dcount == 1 )
{
kvbuf_t *copy = kvbuf_init_zone( malloc_default_purgeable_zone(), tempBuffer->databuf, tempBuffer->datalen );
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, copy, CACHE_ENTRY_TYPE_HOST, ttl, "gni_address", canonicalAddr,
"gni_family", pFamily, "gni_port", pPort, "flags", pCacheFlags, NULL );
}
else
{
kvbuf_free( tempBuffer );
tempBuffer = NULL;
}
}
}
#ifdef CACHE_HOST_ENTRIES
if ( tempBuffer == NULL && localOnlyPID == false && ttl > 0 )
{
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, NULL, CACHE_ENTRY_TYPE_HOST, ttl, "gni_address", canonicalAddr,
"gni_family", pFamily, "gni_port", pPort, "flags", pCacheFlags, NULL );
}
#endif
dsDataListDeallocate( fDirRef, attrTypes );
DSFree( attrTypes );
}
fStatsLock.WaitLock();
fCacheMissByFunction[kDSLUgetnameinfo] += 1;
fStatsLock.SignalLock();
}
else
{
fStatsLock.WaitLock();
fCacheHitsByFunction[kDSLUgetnameinfo] += 1;
fStatsLock.SignalLock();
DbgLog( kLogPlugin, "CCachePlugin::getnameinfo - Cache hit for %s:%s %s:%s", (reqAddress ? canonicalAddr : ""), (pFamily ? pFamily : ""),
(pPort ? pPort : ""), ((flags & NI_DGRAM) == NI_DGRAM ? "udp" : "tcp") );
}
if( NULL != tempBuffer )
{
bool bNameFound = false;
kvbuf_reset( tempBuffer );
kvbuf_next_dict( tempBuffer );
outBuffer = kvbuf_new();
kvbuf_add_dict( outBuffer );
while( (key = kvbuf_next_key(tempBuffer, &valCount)) )
{
if( strcmp(key, "gni_name") == 0 )
{
bNameFound = true;
if( 0 == (flags & NI_NUMERICHOST) )
{
char *pTemp = kvbuf_next_val( tempBuffer );
if( pTemp != NULL )
{
kvbuf_add_key( outBuffer, "gni_name" );
if ( 0 == (flags & NI_NOFQDN) ) {
kvbuf_add_val( outBuffer, pTemp );
}
else {
char *dot = strchr( pTemp, '.' );
if ( dot != NULL )
*dot = '\0';
kvbuf_add_val( outBuffer, pTemp );
}
}
}
}
else if( 0 == (flags & NI_NUMERICSERV) && strcmp(key, "gni_service") == 0 )
{
char* pTemp = kvbuf_next_val(tempBuffer);
if( NULL != pTemp )
{
kvbuf_add_key( outBuffer, "gni_service" );
kvbuf_add_val( outBuffer, pTemp);
}
}
}
if( (NULL != reqAddress) && ((false == bNameFound && 0 == (flags & NI_NAMEREQD)) || (NI_NUMERICHOST == (flags & NI_NUMERICHOST))) )
{
kvbuf_add_key( outBuffer, "gni_name" );
kvbuf_add_val( outBuffer, reqAddress );
}
if( NI_NUMERICSERV == (flags & NI_NUMERICSERV) )
{
kvbuf_add_key( outBuffer, "gni_service" );
kvbuf_add_val( outBuffer, pPort );
}
kvbuf_free( tempBuffer );
tempBuffer = NULL;
}
if( NULL == outBuffer && 0 == (flags & NI_NAMEREQD) )
{
outBuffer = kvbuf_new();
kvbuf_add_dict( outBuffer );
if( NULL != reqAddress )
{
kvbuf_add_key( outBuffer, "gni_name" );
kvbuf_add_val( outBuffer, reqAddress );
}
kvbuf_add_key( outBuffer, "gni_service" );
kvbuf_add_val( outBuffer, pPort );
}
return( outBuffer );
}
#endif
kvbuf_t* CCachePlugin::DSgetmacbyname( kvbuf_t *inBuffer, pid_t inPID )
{
kvbuf_t *outBuffer = NULL;
tDataListPtr attrTypes = NULL;
uint32_t dictCount = kvbuf_reset( inBuffer );
uint32_t valCount = 0;
if( dictCount == 0 )
return NULL;
kvbuf_next_dict( inBuffer );
char *key = kvbuf_next_key( inBuffer, &valCount );
if( strcmp(key, "name") != 0 || valCount == 0 )
return NULL;
char *name = kvbuf_next_val( inBuffer );
if( name == NULL )
return NULL;
outBuffer = FetchFromCache( fLibinfoCache, 0, NULL, "name", name, NULL );
if ( outBuffer == NULL )
{
attrTypes = dsBuildListFromStrings( fDirRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
kDS1AttrENetAddress,
NULL );
if ( attrTypes != NULL )
{
const char *keys[] = { "mac", "name", NULL };
bool localOnlyPID = IsLocalOnlyPID( inPID );
if( localOnlyPID == false )
{
outBuffer = GetRecordListLibInfo( fSearchNodeRef, name, kDSStdRecordTypeEthernets, 1, attrTypes, ParseEthernetEntry, NULL, NULL,
fLibinfoCache, keys );
}
else
{
outBuffer = GetRecordListLibInfo( fFlatFileNodeRef, name, kDSStdRecordTypeEthernets, 1, attrTypes, ParseEthernetEntry, NULL, NULL,
fLibinfoCache, keys );
}
if( outBuffer != NULL )
{
uint32_t dcount = kvbuf_reset( outBuffer );
if( dcount != 1 )
{
kvbuf_free( outBuffer );
outBuffer = NULL;
}
}
if ( outBuffer == NULL && localOnlyPID == false ) {
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, NULL, CACHE_ENTRY_TYPE_HOST, kNegativeCacheTime, "name", name, NULL );
}
dsDataListDeallocate( fDirRef, attrTypes );
DSFree( attrTypes );
}
fStatsLock.WaitLock();
fCacheMissByFunction[kDSLUgetmacbyname] += 1;
fStatsLock.SignalLock();
}
else
{
fStatsLock.WaitLock();
fCacheHitsByFunction[kDSLUgetmacbyname] += 1;
fStatsLock.SignalLock();
DbgLog( kLogPlugin, "CCachePlugin::getmacbyname - Cache hit for %s", name );
}
return( outBuffer );
}
kvbuf_t* CCachePlugin::DSgethostbymac( kvbuf_t *inBuffer, pid_t inPID )
{
kvbuf_t *outBuffer = NULL;
tDataListPtr attrTypes = NULL;
uint32_t dictCount = kvbuf_reset( inBuffer );
uint32_t valCount = 0;
if( dictCount == 0 )
return NULL;
kvbuf_next_dict( inBuffer );
char *key = kvbuf_next_key( inBuffer, &valCount );
if( strcmp(key, "mac") != 0 || valCount == 0 )
return NULL;
char *mac = kvbuf_next_val( inBuffer );
if( mac == NULL )
return NULL;
outBuffer = FetchFromCache( fLibinfoCache, 0, NULL, "mac", mac, NULL );
if ( outBuffer == NULL )
{
attrTypes = dsBuildListFromStrings( fDirRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
kDS1AttrENetAddress,
NULL );
if ( attrTypes != NULL )
{
bool localOnlyPID = IsLocalOnlyPID( inPID );
if( localOnlyPID == false )
{
outBuffer = ValueSearchLibInfo( fSearchNodeRef, kDS1AttrENetAddress, mac, kDSStdRecordTypeEthernets, 1, attrTypes,
ParseEthernetEntry, NULL, NULL, NULL );
}
else
{
outBuffer = ValueSearchLibInfo( fFlatFileNodeRef, kDS1AttrENetAddress, mac, kDSStdRecordTypeEthernets, 1, attrTypes,
ParseEthernetEntry, NULL, NULL, NULL );
}
if( outBuffer != NULL )
{
uint32_t dcount = kvbuf_reset( outBuffer );
if( dcount == 1 )
{
const char *keylist[] = { "mac", "name", NULL };
kvbuf_t *copy = kvbuf_init_zone( malloc_default_purgeable_zone(), outBuffer->databuf, outBuffer->datalen );
AddEntryToCacheWithKeylists( fLibinfoCache, NULL, copy, CACHE_ENTRY_TYPE_HOST, kCacheTime, keylist, NULL );
}
else
{
kvbuf_free( outBuffer );
outBuffer = NULL;
}
}
if ( outBuffer == NULL && localOnlyPID == false ) {
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, NULL, CACHE_ENTRY_TYPE_HOST, kNegativeCacheTime, "mac", mac, NULL );
}
dsDataListDeallocate( fDirRef, attrTypes );
DSFree( attrTypes );
}
fStatsLock.WaitLock();
fCacheMissByFunction[kDSLUgethostbymac] += 1;
fStatsLock.SignalLock();
}
else
{
fStatsLock.WaitLock();
fCacheHitsByFunction[kDSLUgethostbymac] += 1;
fStatsLock.SignalLock();
DbgLog( kLogPlugin, "CCachePlugin::gethostbymac - Cache hit for %s", mac );
}
return( outBuffer );
}
#ifdef HANDLE_DNS_LOOKUPS
kvbuf_t *CCachePlugin::dnsreply_to_kvbuf( dns_reply_t *inReply, const char *inIPv4, const char *inIPv6, pid_t inPID, int32_t *outTTL )
{
kvbuf_t *outBuffer = kvbuf_new();
if( inReply != NULL && inReply->header->ancount > 0 )
{
uint32_t count = inReply->header->ancount;
char buffer[16];
char dnsName[512];
uint32_t index = 0;
while( index < count )
{
dns_resource_record_t *reply = inReply->answer[index];
char *pTarget = NULL;
kvbuf_t *hostInfo = NULL;
SetMaxTTL( *outTTL, reply->ttl );
if( reply->dnstype == fTypeSRV )
{
pTarget = reply->data.SRV->target;
}
else if( reply->dnstype == fTypeMX )
{
pTarget = reply->data.MX->name;
}
if( pTarget != NULL )
{
int length = strlen( pTarget );
if( pTarget[length-1] != '.' )
{
strlcpy( dnsName, pTarget, sizeof(dnsName) );
strlcat( dnsName, ".", sizeof(dnsName ));
pTarget = dnsName;
}
hostInfo = DSgethostbyname_int( pTarget, inIPv4, inIPv6, inPID, false, NULL );
}
int iDictCount = kvbuf_reset( hostInfo );
for( int ii = 0; ii < iDictCount; ii++ )
{
kvbuf_add_dict( outBuffer );
if( reply->dnstype == fTypeSRV )
{
snprintf( buffer, sizeof(buffer), "%u", (unsigned int) reply->data.SRV->port );
kvbuf_add_key( outBuffer, "port" );
kvbuf_add_val( outBuffer, buffer );
}
else if ( reply->dnstype == fTypeMX )
{
kvbuf_add_key( outBuffer, "port" );
kvbuf_add_val( outBuffer, "25" );
}
uint32_t keyCount = kvbuf_next_dict( hostInfo );
for( uint32_t yy = 0; yy < keyCount; yy++ )
{
uint32_t valCount = 0;
char *key = kvbuf_next_key( hostInfo, &valCount );
kvbuf_add_key( outBuffer, key );
for( uint32_t zz = 0; zz < valCount; zz++ )
{
kvbuf_add_val( outBuffer, kvbuf_next_val(hostInfo) );
}
}
}
kvbuf_free( hostInfo );
index++;
}
}
return outBuffer;
}
sDNSLookup *CCachePlugin::CreateAdditionalDNSQueries( sDNSLookup *inDNSLookup, const char *inService, const char *inProtocol, const char *inName,
const char *inSearchDomain, uint16_t inAdditionalInfo )
{
char pQuery[512];
if( inDNSLookup == NULL )
{
inDNSLookup = new sDNSLookup;
}
if( fUnqualifiedSRVAllowed == true && strcmp(inService, "MX") == 0 && inProtocol == NULL )
{
if( inSearchDomain != NULL )
{
snprintf( pQuery, sizeof(pQuery), "%s.%s.", inName, inSearchDomain );
}
else
{
strlcpy( pQuery, inName, sizeof(pQuery) );
}
DbgLog( kLogDebug, "CCachePlugin::CreateAdditionalDNSQueries - Adding MX Record Lookup = %s", pQuery );
inDNSLookup->AddQuery( fClassIN, fTypeMX, pQuery, inAdditionalInfo );
}
else
{
if( inSearchDomain != NULL )
{
snprintf( pQuery, sizeof(pQuery), "_%s._%s.%s.%s.", inService, inProtocol, inName, inSearchDomain );
inDNSLookup->AddQuery( fClassIN, fTypeSRV, pQuery, inAdditionalInfo );
DbgLog( kLogDebug, "CCachePlugin::CreateAdditionalDNSQueries - Adding Service Record Lookup = %s", pQuery );
}
else if( fUnqualifiedSRVAllowed == true )
{
snprintf( pQuery, sizeof(pQuery), "_%s._%s.%s", inService, inProtocol, inName );
inDNSLookup->AddQuery( fClassIN, fTypeSRV, pQuery, inAdditionalInfo );
DbgLog( kLogDebug, "CCachePlugin::CreateAdditionalDNSQueries - Adding Service Record Lookup = %s", pQuery );
}
}
return inDNSLookup;
}
int CCachePlugin::SortPartitionAdditional( dns_resource_record_t **inRecords, int inFirst, int inLast )
{
int up = inFirst;
int down = inLast;
dns_resource_record_t *temp = NULL;
dns_resource_record_t *pivot = inRecords[inFirst];
bool isSRV = (pivot->dnstype == fTypeSRV);
goto partLower;
do
{
temp = inRecords[up];
inRecords[up] = inRecords[down];
inRecords[down] = temp;
partLower:
if( isSRV )
{
uint16_t pivotPriority = pivot->data.SRV->priority;
while ( up < inLast )
{
uint16_t priority = inRecords[up]->data.SRV->priority;
if( priority > pivotPriority )
{
break;
}
else if( priority == pivotPriority )
{
if( inRecords[up]->data.SRV->weight < pivot->data.SRV->weight )
break;
}
up++;
}
while( down > inFirst )
{
uint16_t priority = inRecords[down]->data.SRV->priority;
if( priority < pivotPriority )
{
break;
}
else if( priority == pivotPriority )
{
if( inRecords[up]->data.SRV->weight > pivot->data.SRV->weight )
break;
}
down--;
}
}
else
{
uint16_t pivotPreference = pivot->data.MX->preference;
while (inRecords[up]->data.MX->preference <= pivotPreference && up < inLast)
{
up++;
}
while (inRecords[down]->data.MX->preference > pivotPreference && down > inFirst )
{
down--;
}
}
} while( down > up );
inRecords[inFirst] = inRecords[down];
inRecords[down] = pivot;
return down;
}
void CCachePlugin::QuickSortAdditional( dns_resource_record_t **inRecords, int inFirst, int inLast )
{
int pivotIndex = 0;
if( inFirst < inLast )
{
pivotIndex = SortPartitionAdditional( inRecords, inFirst, inLast );
QuickSortAdditional( inRecords, inFirst, (pivotIndex-1) );
QuickSortAdditional( inRecords, (pivotIndex+1), inLast );
}
}
kvbuf_t* CCachePlugin::DSgetaddrinfo( kvbuf_t *inBuffer, pid_t inPID )
{
kvbuf_t *outBuffer = NULL;
uint32_t dictCount = kvbuf_reset( inBuffer );
uint32_t valCount = 0;
char *pName = NULL;
char *pService = NULL;
char *pProtocol = NULL;
char *pFamily = NULL;
uint32_t protocol = 0;
char *pFlags = NULL;
uint32_t flags = 0;
char *pSockType = NULL;
uint32_t socktype = 0;
uint32_t family = 0;
uint32_t parallel = 0;
bool bResolveName = false;
bool bHaveServiceName = false;
bool bHaveName = false;
char *key = NULL;
if( dictCount == 0 )
return NULL;
kvbuf_next_dict( inBuffer );
while( (key = kvbuf_next_key(inBuffer, &valCount)) )
{
if( strcmp(key, "name") == 0 )
{
pName = kvbuf_next_val( inBuffer );
}
else if( strcmp(key, "service") == 0 )
{
pService = kvbuf_next_val( inBuffer );
}
else if( strcmp(key, "protocol") == 0 )
{
pProtocol = kvbuf_next_val( inBuffer );
if( pProtocol != NULL )
{
protocol = strtoul( pProtocol, NULL, 10 );
}
}
else if( strcmp(key, "socktype") == 0 )
{
pSockType = kvbuf_next_val( inBuffer );
if( pSockType != NULL )
{
socktype = strtoul( pSockType, NULL, 10 );
}
}
else if( strcmp(key, "family") == 0 )
{
pFamily = kvbuf_next_val( inBuffer );
if( pFamily != NULL )
{
family = strtoul( pFamily, NULL, 10 );
}
}
else if( strcmp(key, "ai_flags") == 0 )
{
pFlags = kvbuf_next_val( inBuffer );
if( pFlags != NULL )
{
flags = strtoul( pFlags, NULL, 10 );
}
}
}
bHaveServiceName = (pService != NULL && pService[0] != '\0');
bHaveName = (pName != NULL && pName[0] != '\0');
if ( (flags & AI_PARALLEL) != 0 )
{
parallel = true;
DbgLog( kLogDebug, "CCachePlugin::DSgetaddrinfo - AI_PARALLEL was requested" );
}
if( (bHaveServiceName == false && bHaveName == false) ||
(IPPROTO_UDP == protocol && SOCK_STREAM == socktype) || (IPPROTO_TCP == protocol && SOCK_DGRAM == socktype) )
{
return NULL;
}
if( bHaveName == true )
{
char buffer[16];
uint32_t tempFamily = AF_UNSPEC;
if( inet_pton(AF_INET6, pName, buffer) == 1 )
tempFamily = AF_INET6;
if( tempFamily == AF_UNSPEC && inet_pton(AF_INET, pName, buffer) == 1 )
tempFamily = AF_INET;
if( AF_UNSPEC == tempFamily )
{
if( AI_NUMERICHOST == (flags & AI_NUMERICHOST) )
{
return NULL;
}
else
{
bResolveName = true; }
}
else
{
if( family == AF_UNSPEC || family == tempFamily )
{
family = tempFamily;
}
else
{
return NULL;
}
}
}
const char *socktypeList[] = { NULL, NULL, NULL }; const char *protocolList[] = { NULL, NULL, NULL }; const char *protocolListStr[] = { NULL, NULL, NULL }; char *servicePortList[] = { NULL, NULL, NULL };
char *serviceNameList[] = { NULL, NULL, NULL };
kvbuf_t *pOtherAnswers[] = { NULL, NULL, NULL };
uint32_t serviceCount = 0;
sDNSLookup *pDNSLookup = NULL;
kvbuf_t *pTempBuffer = NULL;
char pTempProtocol[16];
if( (IPPROTO_TCP == protocol || 0 == protocol) && (SOCK_STREAM == socktype || 0 == socktype) )
{
protocolListStr[serviceCount] = "tcp";
protocolList[serviceCount] = "6";
socktypeList[serviceCount] = "1";
serviceCount++;
}
if( (IPPROTO_UDP == protocol || 0 == protocol) && (SOCK_DGRAM == socktype || 0 == socktype) )
{
protocolListStr[serviceCount] = "udp";
protocolList[serviceCount] = "17";
socktypeList[serviceCount] = "2";
serviceCount++;
}
if ( (SOCK_RAW == socktype || 0 == socktype) && 0 != protocol && IPPROTO_UDP != protocol && IPPROTO_TCP != protocol )
{
protocolListStr[serviceCount] = NULL;
snprintf( pTempProtocol, sizeof(pTempProtocol), "%d", protocol );
protocolList[serviceCount] = pTempProtocol;
socktypeList[serviceCount] = "3";
serviceCount++;
}
if( bHaveServiceName == true && bResolveName && (IPPROTO_TCP == protocol || 0 == protocol) && (SOCK_STREAM == socktype || 0 == socktype) &&
strcmp(pService, "smtp") == 0 )
{
protocolListStr[serviceCount] = NULL;
protocolList[serviceCount] = "6";
socktypeList[serviceCount] = "1";
serviceNameList[serviceCount] = strdup( "MX" );
serviceCount++;
}
if ( socktype == SOCK_RAW && pService != NULL && pService[0] != '\0' )
return NULL;
if( bHaveServiceName )
{
char *endptr = NULL;
bool isString = false;
strtol( pService, &endptr, 10 );
if ( endptr != NULL && (*endptr) != '\0' )
isString = true;
int index = serviceCount;
while( index > 0 )
{
index--;
if ( protocolListStr[index] != NULL ) {
if ( isString )
{
kvbuf_t *answer = DSgetservbyname_int( pService, protocolListStr[index], inPID );
if( kvbuf_reset(answer) > 0 )
{
kvbuf_next_dict( answer );
while( (key = kvbuf_next_key(answer, &valCount)) )
{
if( servicePortList[index] == NULL && strcmp(key, "s_port") == 0 )
{
char *pTemp = kvbuf_next_val( answer );
if( pTemp != NULL )
{
servicePortList[index] = strdup( pTemp );
}
}
else if( strcmp(key, "s_name") == 0 )
{
char *pTemp = kvbuf_next_val( answer );
if( pTemp != NULL )
{
serviceNameList[index] = strdup( pTemp );
}
}
}
}
else
{
serviceNameList[index] = strdup( pService ); }
kvbuf_free( answer );
}
else
{
servicePortList[index] = strdup( pService );
}
}
}
}
if( bResolveName == true )
{
const char *pIPv6 = ((AF_UNSPEC == family || AF_INET6 == family) ? "1" : "0");
const char *pIPv4 = ((AF_UNSPEC == family || AF_INET == family) ? "1" : "0");
char *searchDomainUsed = NULL;
int32_t ttl = kDefaultTTLValue;
int iStateIndex = (parallel == 0 && fUnqualifiedSRVAllowed == false ? 1 : 0);
uint32_t iPortListIndex = serviceCount;
while( iPortListIndex > 0 )
{
iPortListIndex--;
if( serviceNameList[iPortListIndex] != NULL )
{
if( protocolListStr[iPortListIndex] != NULL )
{
pOtherAnswers[iPortListIndex] = FetchFromCache( fLibinfoCache, 0, NULL, "sname", serviceNameList[iPortListIndex],
"pname", protocolListStr[iPortListIndex], "dnsname", pName, NULL );
}
else
{
pOtherAnswers[iPortListIndex] = FetchFromCache( fLibinfoCache, 0, NULL, "mxname", pName, NULL );
}
}
}
do
{
switch( fGetAddrStateEngine[iStateIndex] )
{
case kResolveStateCheckDomain:
if( pTempBuffer != NULL && kvbuf_reset(pTempBuffer) > 0 )
{
kvbuf_next_dict( pTempBuffer );
while( (key = kvbuf_next_key( pTempBuffer, &valCount)) )
{
if( strcmp(key, "searchDomainUsed") == 0 )
{
searchDomainUsed = kvbuf_next_val( pTempBuffer );
break;
}
}
if( searchDomainUsed == NULL )
{
DbgLog( kLogDebug, "CCachePlugin::DSgetaddrinfo - Stopping search because no search domain used" );
fGetAddrStateEngine[iStateIndex+1] = kResolveStateDone;
}
else if( pDNSLookup != NULL )
{
DbgLog( kLogPlugin, "CCachePlugin::DSgetaddrinfo - Mismatch - re-issue new Additional Queries" );
DSDelete( pDNSLookup ); pDNSLookup = NULL;
}
}
break;
case kResolveStateBuildExtraQueries:
if( bHaveServiceName == true && serviceCount != 0 )
{
DbgLog( kLogDebug, "CCachePlugin::DSgetaddrinfo - Building Additional Queries" );
for( iPortListIndex = 0; iPortListIndex < serviceCount; iPortListIndex++ )
{
if( serviceNameList[iPortListIndex] != NULL && pOtherAnswers[iPortListIndex] == NULL )
{
pDNSLookup = CreateAdditionalDNSQueries( pDNSLookup, serviceNameList[iPortListIndex], protocolListStr[iPortListIndex],
pName, searchDomainUsed, iPortListIndex );
}
}
DbgLog( kLogDebug, "CCachePlugin::DSgetaddrinfo - Done Building Additional Queries" );
}
else
{
DbgLog( kLogDebug, "CCachePlugin::DSgetaddrinfo - No Additional Queries, no service supplied" );
}
break;
case kResolveStateDoGetHostname: DbgLog( kLogDebug, "CCachePlugin::DSgetaddrinfo - Calling gethostbyname" );
pTempBuffer = DSgethostbyname_int( pName, pIPv4, pIPv6, inPID, parallel, pDNSLookup, &ttl );
if( pTempBuffer == NULL )
{
fGetAddrStateEngine[iStateIndex+1] = kResolveStateDone;
}
break;
case kResolveStateDoExtraQuery:
if( pDNSLookup != NULL )
{
DbgLog( kLogDebug, "CCachePlugin::DSgetaddrinfo - Initiating Additional Queries" );
InitiateDNSQuery( pDNSLookup, false ); }
break;
default:
break;
}
iStateIndex++;
} while( fGetAddrStateEngine[iStateIndex] != kResolveStateDone );
DbgLog( kLogDebug, "CCachePlugin::DSgetaddrinfo - DNS Queries complete" );
if( NULL != pDNSLookup )
{
for( int ii = 0; ii < pDNSLookup->fTotal; ii++ )
{
if( pDNSLookup->fQueryTypes[ii] == fTypeA || pDNSLookup->fQueryTypes[ii] == fTypeAAAA )
break;
dns_reply_t *reply = pDNSLookup->fAnswers[ii];
DbgLog( kLogDebug, "CCachePlugin::DSgetaddrinfo - Additional query %d answers = %d", ii,
(reply != NULL && reply->header != NULL ? reply->header->ancount : 0) );
int tempIndex = pDNSLookup->fAdditionalInfo[ii];
if( (NULL != reply) && (DNS_STATUS_OK == reply->status) )
{
SetMaxTTL( ttl, pDNSLookup->fMinimumTTL[ii] );
if( (NULL != reply->header) && (reply->header->ancount > 1) )
QuickSortAdditional( reply->answer, 0, (reply->header->ancount - 1) );
pOtherAnswers[tempIndex] = dnsreply_to_kvbuf( reply, pIPv4, pIPv6, inPID, &ttl );
}
if( ttl > 0 )
{
kvbuf_t *copy = NULL;
int32_t tempTTL = ttl;
if( pOtherAnswers[tempIndex] != NULL )
{
copy = kvbuf_init_zone( malloc_default_purgeable_zone(), pOtherAnswers[tempIndex]->databuf, pOtherAnswers[tempIndex]->datalen );
}
else
{
SetMaxTTL( tempTTL, pDNSLookup->fMinimumTTL[ii] );
}
if( protocolListStr[tempIndex] != NULL )
{
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, copy, CACHE_ENTRY_TYPE_HOST | CACHE_ENTRY_TYPE_REPLACE, tempTTL,
"sname", serviceNameList[tempIndex], "pname", protocolListStr[tempIndex],
"dnsname", pName, NULL );
}
else
{
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, copy, CACHE_ENTRY_TYPE_HOST | CACHE_ENTRY_TYPE_REPLACE, tempTTL,
"mxname", pName, NULL );
}
}
}
}
}
outBuffer = kvbuf_new();
if( bHaveName == false || bResolveName == false )
{
char pIPv6[INET6_ADDRSTRLEN] = { 0, };
char pIPv4[INET6_ADDRSTRLEN] = { 0, };
char *addresses[2] = { NULL, NULL };
const char *families[2] = { NULL, NULL };
int addressCnt = 0;
if( family == AF_INET || family == AF_UNSPEC )
{
if( bHaveName == false )
{
in_addr_t any = htonl( INADDR_ANY );
in_addr_t loop = htonl( INADDR_LOOPBACK );
inet_ntop( AF_INET, ((flags & AI_PASSIVE) == AI_PASSIVE ? &any : &loop), pIPv4, INET6_ADDRSTRLEN );
addresses[addressCnt] = pIPv4;
}
else
{
addresses[addressCnt] = pName;
}
families[addressCnt] = "2";
addressCnt++;
}
if( family == AF_INET6 || family == AF_UNSPEC )
{
if( bHaveName == false )
{
in6_addr any = IN6ADDR_ANY_INIT;
in6_addr loop = IN6ADDR_LOOPBACK_INIT;
inet_ntop( AF_INET6, ((flags & AI_PASSIVE) == AI_PASSIVE ? &any : &loop), pIPv6, INET6_ADDRSTRLEN );
addresses[addressCnt] = pIPv6;
}
else
{
addresses[addressCnt] = pName;
}
families[addressCnt] = "30";
addressCnt++;
}
while( addressCnt > 0 )
{
addressCnt--;
int index = serviceCount;
while( index > 0 )
{
index--;
if ( bHaveServiceName == true && servicePortList[index] == NULL )
continue;
kvbuf_add_dict( outBuffer );
kvbuf_add_key( outBuffer, "gai_flags");
kvbuf_add_val( outBuffer, pFlags );
kvbuf_add_key( outBuffer, "gai_socktype");
kvbuf_add_val( outBuffer, socktypeList[index] );
kvbuf_add_key( outBuffer, "gai_protocol");
kvbuf_add_val( outBuffer, protocolList[index] );
kvbuf_add_key( outBuffer, "gai_port");
kvbuf_add_val( outBuffer, (servicePortList[index] != NULL ? servicePortList[index] : "0") );
kvbuf_add_key( outBuffer, "gai_address");
kvbuf_add_val( outBuffer, addresses[addressCnt] );
kvbuf_add_key( outBuffer, "gai_family");
kvbuf_add_val( outBuffer, families[addressCnt] );
char *p = strrchr( addresses[addressCnt], '%' );
if (p != NULL)
{
struct in6_addr ipv6Addr;
if ( inet_pton( AF_INET6, addresses[addressCnt], &ipv6Addr ) == 1 && IN6_IS_ADDR_LINKLOCAL( &ipv6Addr ) )
{
char scope[16] = { 0, };
unsigned scopeid = if_nametoindex( p + 1 );
snprintf( scope, sizeof(scope), "%u", scopeid );
kvbuf_add_key( outBuffer, "gai_scopeid" );
kvbuf_add_val( outBuffer, scope );
}
}
if( bHaveName == false && (AI_CANONNAME & flags) == AI_CANONNAME && (AI_PASSIVE & flags) == 0 )
{
kvbuf_add_key( outBuffer, "gai_canonname");
kvbuf_add_val( outBuffer, "localhost" );
}
}
}
}
else
{
enum
{
kProcessAdditional = 0,
kProcessAddress,
kAddValuesToDict,
kDone
};
int iState = kProcessAdditional;
int iNextState = kProcessAddress;
char **ipv6List = NULL;
char **ipv4List = NULL;
size_t listSize = 10;
char ***addressLists = (char ***) malloc( listSize * sizeof(char **) );
int *addressListType = (int *) malloc( listSize * sizeof(int) );
char **portList = (char **) malloc( listSize * sizeof(char *) );
size_t listCount = 0;
char *actualName = NULL;
bool bAddedAddresses = false;
uint32_t iCount = 0;
int otherOffset = 0;
while( iState != kDone )
{
switch( iState )
{
case kProcessAdditional:
while( listCount == 0 && otherOffset < 3 )
{
kvbuf_t *tempBuffer = pOtherAnswers[otherOffset];
if( protocolListStr[otherOffset] == NULL && bAddedAddresses == true )
{
otherOffset++;
continue;
}
iCount = kvbuf_reset( tempBuffer );
for( uint32_t zz = 0; zz < iCount; zz++ )
{
char *port = NULL;
uint32_t vCount;
kvbuf_next_dict( tempBuffer );
while( (key = kvbuf_next_key(tempBuffer, &vCount)) )
{
if( vCount != 0 )
{
char **pWorkingList = NULL;
if( (family == AF_UNSPEC || family == AF_INET6) && strcmp(key, "h_ipv6_addr_list") == 0 )
{
ipv6List = (char **) calloc( vCount + 1, sizeof(char *) );
pWorkingList = ipv6List;
}
else if( (family == AF_UNSPEC || family == AF_INET) && strcmp(key, "h_ipv4_addr_list") == 0 )
{
ipv4List = (char **) calloc( vCount + 1, sizeof(char *) );
pWorkingList = ipv4List;
}
else if( strcmp(key, "h_name") == 0 && actualName == NULL )
{
actualName = kvbuf_next_val( tempBuffer );
}
else if( strcmp(key, "port") == 0 )
{
port = kvbuf_next_val( tempBuffer );
}
if( pWorkingList != NULL )
{
for( uint32_t ii = 0; ii < vCount; ii++ )
{
pWorkingList[ii] = kvbuf_next_val( tempBuffer );
}
}
}
}
if( (family == AF_UNSPEC || family == AF_INET6) && ipv6List != NULL )
{
addressLists[listCount] = ipv6List;
addressListType[listCount] = AF_INET6;
portList[listCount] = port;
listCount++;
ipv6List = NULL;
}
if( (family == AF_UNSPEC || family == AF_INET) && ipv4List != NULL )
{
addressLists[listCount] = ipv4List;
addressListType[listCount] = AF_INET;
portList[listCount] = port;
listCount++;
ipv4List = NULL;
}
if ( listCount >= listSize ) {
listSize += 10;
addressLists = (char ***) reallocf( addressLists, listSize * sizeof(char **) );
addressListType = (int *) reallocf( addressListType, listSize * sizeof(int) );
portList = (char **) reallocf( portList, listSize * sizeof(char *) );
if ( addressLists == NULL || addressListType == NULL || portList == NULL )
abort();
}
}
otherOffset++; }
if( listCount > 0 )
{
iNextState = kProcessAdditional; iState = kAddValuesToDict;
continue;
}
else if( bAddedAddresses == false ) {
iState = kProcessAddress;
continue;
}
else {
iState = kDone;
continue;
}
break;
case kProcessAddress:
iCount = kvbuf_reset( pTempBuffer );
if( iCount > 0 )
{
uint32_t vCount;
kvbuf_next_dict( pTempBuffer );
while( (key = kvbuf_next_key(pTempBuffer, &vCount)) )
{
if( vCount != 0 )
{
char **pWorkingList = NULL;
if( (family == AF_UNSPEC || family == AF_INET6) && strcmp(key, "h_ipv6_addr_list") == 0 )
{
ipv6List = (char **) calloc( vCount+1, sizeof(char *) );
pWorkingList = ipv6List;
}
else if( (family == AF_UNSPEC || family == AF_INET) && strcmp(key, "h_ipv4_addr_list") == 0 )
{
ipv4List = (char **) calloc( vCount+1, sizeof(char *) );
pWorkingList = ipv4List;
}
else if( strcmp(key, "h_name") == 0 && actualName == NULL )
{
actualName = kvbuf_next_val( pTempBuffer );
}
if( pWorkingList != NULL )
{
for( uint32_t ii = 0; ii < vCount; ii++ )
{
pWorkingList[ii] = kvbuf_next_val( pTempBuffer );
}
}
}
}
if( (family == AF_UNSPEC || family == AF_INET6) && ipv6List != NULL )
{
addressLists[listCount] = ipv6List;
addressListType[listCount] = AF_INET6;
portList[listCount] = NULL;
listCount++;
ipv6List = NULL;
}
if( (family == AF_UNSPEC || family == AF_INET) && ipv4List != NULL )
{
addressLists[listCount] = ipv4List;
addressListType[listCount] = AF_INET;
portList[listCount] = NULL;
listCount++;
ipv4List = NULL;
}
if ( listCount >= listSize ) {
listSize += 10;
addressLists = (char ***) reallocf( addressLists, listSize * sizeof(char **) );
addressListType = (int *) reallocf( addressListType, listSize * sizeof(int) );
portList = (char **) reallocf( portList, listSize * sizeof(char *) );
if ( addressLists == NULL || addressListType == NULL || portList == NULL )
abort();
}
}
iNextState = kDone;
case kAddValuesToDict:
for ( size_t iListIndex = 0; iListIndex < listCount; iListIndex++ )
{
char **tempList = addressLists[iListIndex];
int addrIndex = 0;
char *address;
while( (address = tempList[addrIndex]) != NULL )
{
int index = serviceCount;
while ( index > 0 )
{
index--;
if ( bHaveServiceName == true && portList[iListIndex] == NULL && servicePortList[index] == NULL )
continue;
kvbuf_add_dict( outBuffer );
kvbuf_add_key( outBuffer, "gai_flags");
kvbuf_add_val( outBuffer, pFlags );
kvbuf_add_key( outBuffer, "gai_socktype");
kvbuf_add_val( outBuffer, socktypeList[(iNextState == kProcessAdditional ? (otherOffset - 1) : index)] );
kvbuf_add_key( outBuffer, "gai_protocol");
kvbuf_add_val( outBuffer, protocolList[(iNextState == kProcessAdditional ? (otherOffset - 1) : index)] );
kvbuf_add_key( outBuffer, "gai_port");
if( portList[iListIndex] != NULL )
{
kvbuf_add_val( outBuffer, portList[iListIndex] );
}
else
{
kvbuf_add_val( outBuffer, (servicePortList[index] != NULL ? servicePortList[index] : "0") );
}
if( addressListType[iListIndex] == AF_INET6 )
{
char *p = strrchr( address, '%' );
if (p != NULL)
{
struct in6_addr ipv6Addr;
if ( inet_pton( AF_INET6, address, &ipv6Addr ) == 1 && IN6_IS_ADDR_LINKLOCAL( &ipv6Addr ) )
{
char scope[16] = { 0, };
unsigned scopeid = if_nametoindex( p + 1 );
snprintf( scope, sizeof(scope), "%u", scopeid );
kvbuf_add_key( outBuffer, "gai_scopeid" );
kvbuf_add_val( outBuffer, scope );
}
}
kvbuf_add_key( outBuffer, "gai_address");
kvbuf_add_val( outBuffer, address );
kvbuf_add_key( outBuffer, "gai_family");
kvbuf_add_val( outBuffer, "30" );
}
else
{
kvbuf_add_key( outBuffer, "gai_address");
kvbuf_add_val( outBuffer, address );
kvbuf_add_key( outBuffer, "gai_family");
kvbuf_add_val( outBuffer, "2" );
}
if( (AI_CANONNAME & flags) == AI_CANONNAME && actualName != NULL )
{
kvbuf_add_key( outBuffer, "gai_canonname");
kvbuf_add_val( outBuffer, actualName );
}
if ( iNextState == kProcessAdditional )
break;
};
addrIndex++;
}
DSFree( addressLists[iListIndex] );
addressListType[iListIndex] = AF_UNSPEC;
portList[iListIndex] = NULL;
actualName = NULL;
bAddedAddresses = true;
}
listCount = 0;
break;
default:
break;
}
iState = iNextState;
};
DSFree( addressLists );
DSFree( addressListType );
DSFree( portList );
}
while( serviceCount > 0 )
{
serviceCount--;
DSFree( servicePortList[serviceCount] );
DSFree( serviceNameList[serviceCount] );
}
int otherOffset = 0;
while( otherOffset < 3 )
{
kvbuf_free( pOtherAnswers[otherOffset] );
pOtherAnswers[otherOffset] = NULL;
otherOffset++;
}
if( pDNSLookup != NULL )
{
DSDelete( pDNSLookup );
}
if ( (pTempBuffer == NULL || pTempBuffer->datalen == sizeof(int32_t)) && outBuffer != NULL && outBuffer->datalen == sizeof(int32_t) )
{
kvbuf_free( outBuffer );
outBuffer = NULL;
}
kvbuf_free( pTempBuffer );
return outBuffer;
}
kvbuf_t* CCachePlugin::DSdns_proxy( kvbuf_t *inBuffer, pid_t inPID )
{
kvbuf_t *outBuffer = NULL;
uint32_t dictCount = kvbuf_reset( inBuffer );
char *domain = NULL;
char *key = NULL;
uint16_t dnsclass = 0xffff;
uint16_t dnstype = 0xffff;
uint32_t searchType = 0;
uint32_t valCount = 0;
if( dictCount == 0 )
return NULL;
kvbuf_next_dict( inBuffer );
while( (key = kvbuf_next_key(inBuffer, &valCount)) )
{
if( strcmp(key, "domain") == 0 )
{
domain = kvbuf_next_val( inBuffer );
}
else if( strcmp(key, "class") == 0 )
{
char *pTemp = kvbuf_next_val( inBuffer );
if( NULL != pTemp )
{
dnsclass = strtol( pTemp, NULL, 10 );
}
}
else if( strcmp(key, "type") == 0 )
{
char *pTemp = kvbuf_next_val( inBuffer );
if( NULL != pTemp )
{
dnstype = strtol( pTemp, NULL, 10 );
}
}
else if( strcmp(key, "search") == 0 )
{
char *pTemp = kvbuf_next_val( inBuffer );
if( NULL != pTemp )
{
searchType = strtol( pTemp, NULL, 10 );
}
}
}
if( 0xffff == dnsclass || 0xffff == dnstype || NULL == domain )
{
return NULL;
}
dns_handle_t dns = dns_open( NULL );
int32_t bufferlen = 0;
uint32_t fromlen = sizeof(struct sockaddr_storage);
struct sockaddr *from;
char buffer[DNS_BUFFER_SIZE];
if( dns )
{
int slot = AddToDNSThreads();
from = (struct sockaddr *) calloc( 1, sizeof(sockaddr_storage) );
if( searchType == 0 )
{
bufferlen = dns_query( dns, domain, dnsclass, dnstype, buffer, DNS_BUFFER_SIZE, from, &fromlen );
}
else
{
bufferlen = dns_search( dns, domain, dnsclass, dnstype, buffer, DNS_BUFFER_SIZE, from, &fromlen );
}
RemoveFromDNSThreads( slot );
if( bufferlen > 0 )
{
outBuffer = kvbuf_new();
kvbuf_add_dict( outBuffer );
kvbuf_add_key( outBuffer, "data" );
kvbuf_add_val_len( outBuffer, buffer, bufferlen );
inet_ntop( from->sa_family, (char *)(from) + (from->sa_family == AF_INET6 ? 8 : 4), buffer, DNS_BUFFER_SIZE );
kvbuf_add_key( outBuffer, "server" );
kvbuf_add_val( outBuffer, buffer );
}
DSFree( from );
dns_free( dns );
}
return outBuffer;
}
#endif
kvbuf_t* CCachePlugin::DSgetbootpbyhw( kvbuf_t *inBuffer, pid_t inPID )
{
kvbuf_t *outBuffer = NULL;
tDataListPtr attrTypes = NULL;
uint32_t dictCount = kvbuf_reset( inBuffer );
uint32_t valCount = 0;
sCacheValidation *theValidation = NULL;
char buffer[32];
if( dictCount == 0 )
return NULL;
kvbuf_next_dict( inBuffer );
char *key = kvbuf_next_key( inBuffer, &valCount );
if( strcmp(key, "hw") != 0 || valCount == 0 )
return NULL;
char *hw = kvbuf_next_val( inBuffer );
if( hw == NULL )
return NULL;
struct ether_addr etherStorage;
struct ether_addr *etherAddr = myether_aton( hw, ðerStorage );
if( etherAddr != NULL )
{
snprintf( buffer, sizeof(buffer), "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", etherAddr->octet[0], etherAddr->octet[1], etherAddr->octet[2], etherAddr->octet[3], etherAddr->octet[4], etherAddr->octet[5] );
hw = buffer;
}
else
return NULL;
outBuffer = FetchFromCache( fLibinfoCache, 0, NULL, "bp_hw", hw, NULL );
if ( outBuffer == NULL )
{
attrTypes = dsBuildListFromStrings( fDirRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
kDS1AttrENetAddress,
kDSNAttrIPAddress,
kDSNAttrIPAddressAndENetAddress,
kDS1AttrBootFile,
NULL );
if ( attrTypes != NULL )
{
const char *keys[2] = { NULL, hw };
bool localOnlyPID = IsLocalOnlyPID( inPID );
if( localOnlyPID == false )
{
outBuffer = ValueSearchLibInfo( fSearchNodeRef, kDS1AttrENetAddress, hw, kDSStdRecordTypeComputers, 1, attrTypes,
ParseBootpEntry, NULL, keys, &theValidation, eDSiExact );
}
else
{
outBuffer = ValueSearchLibInfo( fFlatFileNodeRef, kDS1AttrENetAddress, hw, kDSStdRecordTypeComputers, 1, attrTypes,
ParseBootpEntry, NULL, keys, &theValidation, eDSiExact );
}
if( outBuffer != NULL )
{
uint32_t dcount = kvbuf_reset( outBuffer );
if( dcount == 1 )
{
const char *keys2[] = { "bp_hw", "bp_addr", NULL };
kvbuf_t *copy = kvbuf_init_zone( malloc_default_purgeable_zone(), outBuffer->databuf, outBuffer->datalen );
AddEntryToCacheWithKeys( fLibinfoCache, theValidation, copy, CACHE_ENTRY_TYPE_COMPUTER, 60, keys2 );
}
else
{
kvbuf_free( outBuffer );
outBuffer = NULL;
}
}
if ( outBuffer == NULL && localOnlyPID == false ) {
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, NULL, CACHE_ENTRY_TYPE_COMPUTER, 60, "bp_hw", hw, NULL );
}
dsDataListDeallocate( fDirRef, attrTypes );
DSFree( attrTypes );
}
fStatsLock.WaitLock();
fCacheMissByFunction[kDSLUgetbootpbyhw] += 1;
fStatsLock.SignalLock();
}
else
{
fStatsLock.WaitLock();
fCacheHitsByFunction[kDSLUgetbootpbyhw] += 1;
fStatsLock.SignalLock();
DbgLog( kLogPlugin, "CCachePlugin::getbootpbyhw - Cache hit for %s", hw );
}
DSRelease( theValidation );
return( outBuffer );
}
kvbuf_t* CCachePlugin::DSgetbootpbyaddr( kvbuf_t *inBuffer, pid_t inPID )
{
kvbuf_t *outBuffer = NULL;
tDataListPtr attrTypes = NULL;
uint32_t dictCount = kvbuf_reset( inBuffer );
uint32_t valCount = 0;
sCacheValidation *theValidation = NULL;
if( dictCount == 0 )
return NULL;
kvbuf_next_dict( inBuffer );
char *key = kvbuf_next_key( inBuffer, &valCount );
if( strcmp(key, "addr") != 0 || valCount == 0 )
return NULL;
char *addr = kvbuf_next_val( inBuffer );
if( addr == NULL )
return NULL;
outBuffer = FetchFromCache( fLibinfoCache, 0, NULL, "bp_addr", addr, NULL );
if ( outBuffer == NULL )
{
attrTypes = dsBuildListFromStrings( fDirRef,
kDSNAttrMetaNodeLocation,
kDSNAttrRecordName,
kDS1AttrENetAddress,
kDSNAttrIPAddress,
kDSNAttrIPAddressAndENetAddress,
kDS1AttrBootFile,
NULL );
if ( attrTypes != NULL )
{
const char *keys[2] = { addr, NULL };
bool localOnlyPID = IsLocalOnlyPID( inPID );
if( localOnlyPID == false )
{
outBuffer = ValueSearchLibInfo( fSearchNodeRef, kDSNAttrIPAddress, addr, kDSStdRecordTypeComputers, 1, attrTypes,
ParseBootpEntry, NULL, keys, NULL );
}
else
{
outBuffer = ValueSearchLibInfo( fFlatFileNodeRef, kDSNAttrIPAddress, addr, kDSStdRecordTypeComputers, 1, attrTypes,
ParseBootpEntry, NULL, keys, NULL );
}
if( outBuffer != NULL )
{
uint32_t dcount = kvbuf_reset( outBuffer );
if( dcount == 1 )
{
const char *keys2[] = { "bp_hw", "bp_addr", NULL };
kvbuf_t *copy = kvbuf_init_zone( malloc_default_purgeable_zone(), outBuffer->databuf, outBuffer->datalen );
AddEntryToCacheWithKeys( fLibinfoCache, theValidation, copy, CACHE_ENTRY_TYPE_COMPUTER, 60, keys2 );
}
else
{
kvbuf_free( outBuffer );
outBuffer = NULL;
}
}
if ( outBuffer == NULL && localOnlyPID == false ) {
AddEntryToCacheWithMultiKey( fLibinfoCache, NULL, NULL, CACHE_ENTRY_TYPE_COMPUTER, 60, "bp_addr", addr, NULL );
}
dsDataListDeallocate( fDirRef, attrTypes );
DSFree( attrTypes );
}
fStatsLock.WaitLock();
fCacheMissByFunction[kDSLUgetbootpbyaddr] += 1;
fStatsLock.SignalLock();
}
else
{
fStatsLock.WaitLock();
fCacheHitsByFunction[kDSLUgetbootpbyaddr] += 1;
fStatsLock.SignalLock();
DbgLog( kLogPlugin, "CCachePlugin::getbootpbyaddr - Cache hit for %s", addr );
}
DSRelease( theValidation );
return( outBuffer );
}
#pragma mark -
#pragma mark Support Routines
#pragma mark -
sCacheContextData* CCachePlugin::MakeContextData ( void )
{
sCacheContextData *pOut = NULL;
pOut = (sCacheContextData *) ::calloc( 1, sizeof(sCacheContextData) );
if ( pOut != NULL )
{
pOut->fNodeName = NULL;
pOut->fUID = 99;
pOut->fEffectiveUID = 99;
}
return( pOut );
}
SInt32 CCachePlugin::CleanContextData ( sCacheContextData *inContext )
{
SInt32 siResult = eDSNoErr;
if (( inContext == NULL ) || ( gCacheNode == NULL ))
{
siResult = eDSBadContextData;
}
else
{
DSFreeString(inContext->fNodeName);
DSFree( inContext );
}
return( siResult );
}
void CCachePlugin::ContinueDeallocProc ( void* inContinueData )
{
sCacheContinueData *pContinue = (sCacheContinueData *)inContinueData;
DSFree( pContinue );
}
void CCachePlugin::ContextDeallocProc ( void* inContextData )
{
sCacheContextData *pContext = (sCacheContextData *) inContextData;
if ( pContext != NULL )
{
CleanContextData( pContext );
}
}