Common.mm   [plain text]



#include "Common.h"
#include <PasswordServer/ReplicaFile.h>
#include <Foundation/Foundation.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <time.h>
#include <sys/sysctl.h>
#include <unistd.h>

//---------------------------------------------------------------------------------------------------------------
//	nest_log_time
//---------------------------------------------------------------------------------------------------------------

void nest_log_time( FILE *inFile )
{
	time_t now;
	struct tm nowStruct;
	char timeStr[256];
	
	if ( inFile == NULL )
		return;
	
	time(&now);
	localtime_r( &now, &nowStruct );
	strftime( timeStr, sizeof(timeStr),"%F %T ", &nowStruct );
	fprintf( inFile, "%s", timeStr );
}


//---------------------------------------------------------------------------------------------------------------
//	UpdateReplicaList
//---------------------------------------------------------------------------------------------------------------

void UpdateReplicaList(const char *inOldIP, const char* inNewIP)
{
	long						status				= eDSNoErr;
	tAttributeValueEntry	   *pAttrValueEntry		= NULL;
	tAttributeValueEntry	   *pNewAttrValue		= NULL;
	unsigned long				index				= 0;
	unsigned long				nodeCount			= 0;
	tRecordReference			recordRef			= 0;
	tDirReference				dsRef				= 0;
	tDataNode				   *attrTypeNode		= NULL;
	CFMutableDictionaryRef		replicaDict			= NULL;
	DSUtils						dsUtils;
	CFStringRef					replicaNameString	= NULL;
	NSString					*replicaListString	= nil;
	char						fullRecordName[256];
	NSString					*replicaIDString	= nil;
	
	status = dsUtils.GetLocallyHostedNodeList();
	if ( status != eDSNoErr )
		return;
	
	dsRef = dsUtils.GetDSRef();
	
	do
	{
		nodeCount = dsUtils.GetLocallyHostedNodeCount();
		for ( index = 1; index <= nodeCount; index++ )
		{
			status = dsUtils.OpenLocallyHostedNode( index );
			if ( status != eDSNoErr )
				continue;
			
			status = dsUtils.OpenRecord( kDSStdRecordTypeConfig, kPWConfigDefaultRecordName, &recordRef );
			if ( status != eDSNoErr )
				continue;
			
			attrTypeNode = dsDataNodeAllocateString( 0, kDS1AttrPasswordServerList );
			status = dsGetRecordAttributeValueByIndex( recordRef, attrTypeNode, 1, &pAttrValueEntry );
			if ( status != eDSNoErr )
				break;
			
			ReplicaFile *repList = [[ReplicaFile alloc] initWithXMLStr:(char *)&(pAttrValueEntry->fAttributeValueData.fBufferData)];
			replicaNameString = [repList getNameFromIPAddress:inOldIP];
			if ( replicaNameString == NULL )
				continue;
			
			replicaDict = [repList getReplicaByName:replicaNameString];
			if ( replicaDict != NULL )
			{
				[repList addIPAddress:inNewIP orReplaceIP:inOldIP inReplica:replicaDict];
				CFRelease( replicaDict );
			}
			
			replicaListString = (NSString *)[repList xmlString];
			if ( replicaListString != nil )
			{
				// set the attribute
				pNewAttrValue = dsAllocAttributeValueEntry(dsRef, pAttrValueEntry->fAttributeValueID, (char *)[replicaListString UTF8String], strlen([replicaListString UTF8String]) );
				[replicaListString release];
				replicaListString = nil;
			}
			if ( pNewAttrValue == NULL )
				continue;
			
			status = dsSetAttributeValue( recordRef, attrTypeNode, pNewAttrValue );
			debugerr( status, "dsSetAttributeValue(#3) = %ld\n", status );
			
			dsDeallocAttributeValueEntry( dsRef, pNewAttrValue );
			pNewAttrValue = NULL;
			
			if (recordRef != 0) {
				dsCloseRecord( recordRef );
				recordRef = 0;
			}
			
			replicaIDString = (NSString *)[repList getUniqueID];
			if ( replicaIDString != nil )
			{
				// update record passwordserver_HASH
				strcpy( fullRecordName, kPWConfigRecordPrefix );
				strcat( fullRecordName, [replicaIDString UTF8String] );
				
				status = dsUtils.OpenRecord( kDSStdRecordTypeConfig, fullRecordName, &recordRef );
				if ( status != eDSNoErr )
					continue;
				
				status = dsGetRecordAttributeValueByIndex( recordRef, attrTypeNode, 1, &pAttrValueEntry );
				if ( status != eDSNoErr )
					break;
				
				ReplicaFile *repList2 = [[ReplicaFile alloc] initWithXMLString:[NSString stringWithUTF8String:(char *)&(pAttrValueEntry->fAttributeValueData.fBufferData)]];
				replicaNameString = [repList2 getNameFromIPAddress:inOldIP];
				replicaDict = [repList2 getReplicaByName:replicaNameString];
				if ( replicaDict != NULL )
				{
					[repList2 addIPAddress:inNewIP orReplaceIP:inOldIP inReplica:replicaDict];
					CFRelease( replicaDict );
				}
				
				replicaListString = (NSString *)[repList2 xmlString];
				if ( replicaListString != NULL )
				{
					// set the attribute
					pNewAttrValue = dsAllocAttributeValueEntry( dsRef, pAttrValueEntry->fAttributeValueID, (char *)[replicaListString UTF8String], strlen([replicaListString UTF8String]) );
					[replicaListString release];
					replicaListString = nil;
				}
				
				if ( pNewAttrValue != NULL )
				{
					status = dsSetAttributeValue( recordRef, attrTypeNode, pNewAttrValue );
					debugerr( status, "dsSetAttributeValue(#4) = %ld\n", status );
					
					dsDeallocAttributeValueEntry( dsRef, pNewAttrValue );
					pNewAttrValue = NULL;
				}
				
				if (recordRef != 0) {
					dsCloseRecord( recordRef );
					recordRef = 0;
				}
			}
		}
	}
	while(false);
	
	if (recordRef != 0) {
		dsCloseRecord( recordRef );
		recordRef = 0;
	}
}


//---------------------------------------------------------------------------------------------------------------
//	GetPWServerAddresses
//
//	Returns: a comma-delimited list of IP addresses in each locally hosted node.
//---------------------------------------------------------------------------------------------------------------

void GetPWServerAddresses(char *outAddressStr)
{
    long						status				= eDSNoErr;
	tAttributeValueEntry	   *pAttrValueEntry		= NULL;
    unsigned long				index				= 0;
    unsigned long				nodeCount			= 0;
    tRecordReference			recordRef			= 0;
    tDataNode				   *attrTypeNode		= nil;
    DSUtils						dsUtils;
	
    *outAddressStr = '\0';
    
	status = dsUtils.GetLocallyHostedNodeList();
	if ( status != eDSNoErr )
		return;
	
    do
    {
		nodeCount = dsUtils.GetLocallyHostedNodeCount();
        for ( index = 1; index <= nodeCount; index++ )
        {
			status = dsUtils.OpenLocallyHostedNode( index );
			if ( status != eDSNoErr )
				continue;
            
			status = dsUtils.OpenRecord( kDSStdRecordTypeConfig, kPWConfigDefaultRecordName, &recordRef );
			if ( status != eDSNoErr )
				continue;
            
            attrTypeNode = dsDataNodeAllocateString( 0, kDS1AttrPasswordServerLocation );
            status = dsGetRecordAttributeValueByIndex( recordRef, attrTypeNode, 1, &pAttrValueEntry );
            if ( status != eDSNoErr )
				break;
            
            if ( outAddressStr[0] != '\0' )
                strcat( outAddressStr, "," );
            strcat( outAddressStr, (char *)&(pAttrValueEntry->fAttributeValueData.fBufferData) );
            
            if (recordRef != 0) {
                dsCloseRecord( recordRef );
                recordRef = 0;
            }
        }
    }
    while(false);
	
	if ( outAddressStr[0] == '\0' )
	{
		do
		{
			status = dsUtils.OpenLocalLDAPNode( NULL, NULL );
			if ( status != eDSNoErr )
				break;
			
			status = dsUtils.OpenRecord( kDSStdRecordTypeConfig, kPWConfigDefaultRecordName, &recordRef );
			if ( status != eDSNoErr )
				break;
			
			attrTypeNode = dsDataNodeAllocateString( 0, kDS1AttrPasswordServerLocation );
			status = dsGetRecordAttributeValueByIndex( recordRef, attrTypeNode, 1, &pAttrValueEntry );
			if ( status != eDSNoErr )
				break;
			
			if ( outAddressStr[0] != '\0' )
				strcat( outAddressStr, "," );
			strcat( outAddressStr, (char *)&(pAttrValueEntry->fAttributeValueData.fBufferData) );
			
			if (recordRef != 0) {
				dsCloseRecord( recordRef );
				recordRef = 0;
			}
		}
		while(false);
	}
	
    if (recordRef != 0) {
        dsCloseRecord( recordRef );
        recordRef = 0;
    }
}


//---------------------------------------------------------------------------------------------------------------
//	SetPWServerAddress
//
//	inOutAddressStr - an address is required on input if <inHost> is false.
//					- an address is returned on output if <inHost> is true and <inOutAddressStr> is non-null.
//---------------------------------------------------------------------------------------------------------------

void SetPWServerAddress(const char *inUsername, const char *inPassword, char *inOutAddressStr, bool inHost, const char *inReplicaList, const char *inReplicaRecordName, SetupActionType action )
{
	long				status				= eDSNoErr;
	long				status2				= eDSNoErr;
	char				*addressStr			= nil;
	DSUtils				ldapNode;
	char				fullRecordName[256];
	
	if ( action == kSetupActionGeneral )
	{
		// for -hostpasswordserver, <inAddressStr> will be nil, and we should
		// use this machine's IP address
		if ( inHost )
		{
			addressStr = (char *)malloc(30);
			GetMyAddressAsString( addressStr );
			//printf("%s\n",addressStr);
			
			if ( inOutAddressStr )
				strcpy( inOutAddressStr, addressStr );
		}
		else
		if ( inOutAddressStr != NULL )
		{
			long addrLen;
			
			addrLen = strlen(inOutAddressStr);
			addressStr = (char *)malloc(addrLen+1);
			strcpy(addressStr, inOutAddressStr);
		}
		
		if ( addressStr != NULL )
		{
			// Note: if setting up a replica, do not update the old Jaguar attribute in LDAP. It should point at the LDAP master, not the replica.
			if ( action != kSetupActionSetupReplica )
			{
				status = SetPWConfigAttribute( kPWConfigDefaultRecordName, kDS1AttrPasswordServerLocation, addressStr, inUsername, inPassword, &ldapNode );
				status2 = SetPWConfigAttributeLocal( kPWConfigDefaultRecordName, kDS1AttrPasswordServerLocation, addressStr, true, true );
			}
		}
	}
	
	if ( inReplicaList != NULL )
	{
		status = SetPWConfigAttribute( kPWConfigDefaultRecordName, kDS1AttrPasswordServerList, inReplicaList, inUsername, inPassword, &ldapNode );
		if ( inReplicaRecordName != NULL )
		{
			strcpy( fullRecordName, kPWConfigRecordPrefix );
			strcat( fullRecordName, inReplicaRecordName );
			status = SetPWConfigAttribute( fullRecordName, kDS1AttrPasswordServerList, inReplicaList, inUsername, inPassword, &ldapNode );
		}
	}
	
	if (addressStr != nil) {
        free(addressStr);
    }
}

long RemovePWSListAttributeAndPWSReplicaRecord( const char *inUsername, const char *inPassword )
{
	DSUtils						ldapNode;
	long						status				= eDSNoErr;
	tRecordReference			pwConfigRecordRef	= 0;
	tRecordReference			recordRef			= 0;
	tDataNodePtr				attrName			= NULL;
	tDirReference				dsRef				= 0;
	tAttributeValueEntryPtr		attrValueEntry		= NULL;
	NSString*					replicaIDString		= nil;
	char*						pwsListAttrStr		= NULL;
	char						pwsReplicaRecordName[96];

	status = ldapNode.OpenLocalLDAPNode( inUsername, inPassword );

	if( status == eDSNoErr ) {
		dsRef = ldapNode.GetDSRef();
		status = ldapNode.OpenRecord( kDSStdRecordTypeConfig, kPWConfigDefaultRecordName, &pwConfigRecordRef, true );
	}
	
	// get the  replica ID string from the ID key in the kDS1AttrPasswordServerList attribute
	if( status == eDSNoErr )
		attrName = dsDataNodeAllocateString( dsRef, kDS1AttrPasswordServerList );

	if( status == eDSNoErr && attrName != NULL )
		status = dsGetRecordAttributeValueByIndex( pwConfigRecordRef, attrName, 1, &attrValueEntry );
	
	if( status == eDSNoErr ) {
		pwsListAttrStr = attrValueEntry->fAttributeValueData.fBufferData;
		if( pwsListAttrStr != NULL ) {
			ReplicaFile *replicaFile = [[ReplicaFile alloc] initWithXMLStr:pwsListAttrStr];
			replicaIDString = (NSString *)[replicaFile getUniqueID];
		}
	}
	
	if( [replicaIDString length] > 0 ) {
		sprintf( pwsReplicaRecordName, "%s_%s", kPWConfigDefaultRecordName, [replicaIDString UTF8String] );
		status = ldapNode.OpenRecord( kDSStdRecordTypeConfig, pwsReplicaRecordName, &recordRef, false );
		if( status == eDSNoErr )
			status = dsDeleteRecord( recordRef );
		if( status == eDSRecordNotFound )
			status = eDSNoErr;
		if( status != eDSNoErr )
			dsCloseRecord( recordRef );
		recordRef = 0;
	}

	if( attrName != NULL )
		status = dsRemoveAttribute( pwConfigRecordRef, attrName);

	if( attrName != NULL ) {
		dsDataNodeDeAllocate( dsRef, attrName );
		attrName = NULL;
	}

	if( attrValueEntry != NULL ) {
		dsDeallocAttributeValueEntry( dsRef, attrValueEntry );
		attrValueEntry = NULL;
	}

	if (recordRef != 0) {
		dsCloseRecord( recordRef );
		recordRef = 0;
	}

	if (pwConfigRecordRef != 0) {
		dsCloseRecord( pwConfigRecordRef );
		pwConfigRecordRef = 0;
	}

	return status;
}

//-----------------------------------------------------------------------------
//	 GetMyAddressAsString
//-----------------------------------------------------------------------------

void GetMyAddressAsString( char *outAddressStr )
{
	unsigned char ip[4];
    struct sockaddr_in server_addr;
	
	get_myaddress(&server_addr);
    memcpy(ip, &server_addr.sin_addr.s_addr, 4);
    sprintf(outAddressStr, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
}



//---------------------------------------------------------------------------------------------------------------
//	SetPWConfigAttribute
//---------------------------------------------------------------------------------------------------------------

long SetPWConfigAttribute( const char *inRecordName, const char *inAttributeName, const char *inValue, const char *inUser, const char *inPassword, DSUtils *ldapNode )
{
	long status = eDSNoErr;
	
	// As of Slate, we're not using password server for the local node anymore
	//status = SetPWConfigAttributeLocal( inRecordName, inAttributeName, inValue );
	status = SetPWConfigAttributeLDAP( inRecordName, inAttributeName, inValue, inUser, inPassword, ldapNode );
	
	return status;
}


long SetPWConfigAttributeLocal( const char *inRecordName, const char *inAttributeName, const char *inValue, bool inCreateRecord, bool inParentOnly )
{
    long						status				= eDSNoErr;
    tAttributeValueEntry	   *pExistingAttrValue	= NULL;
    tAttributeValueEntry	   *pNewAttrValue		= NULL;
    unsigned long				index				= 0;
    unsigned long				nodeCount			= 0;
	tRecordReference			recordRef			= 0;
    tDataNode				   *attrTypeNode		= nil;
    tDirReference				dsRef				= 0;
	DSUtils						dsUtils;
	
	status = dsUtils.GetLocallyHostedNodeList();
	if ( status != eDSNoErr ) {
		debug ( "GetLocallyHostedNodeList = %ld.\n", status );
		return status;
	}
	
	dsRef = dsUtils.GetDSRef();
	
    do
    {
		nodeCount = dsUtils.GetLocallyHostedNodeCount();
        for ( index = 1; index <= nodeCount; index++ )
        {
			if ( inParentOnly )
			{
				status = dsUtils.OpenNodeByName( "/Local/..", NULL, NULL );
				if ( status != eDSNoErr )
					break;
			}
			else
			{
				status = dsUtils.OpenLocallyHostedNode( index );
			}
			if ( status != eDSNoErr )
				continue;
            
			status = dsUtils.OpenRecord( kDSStdRecordTypeConfig, inRecordName, &recordRef, inCreateRecord );
            if ( status != eDSNoErr )
				continue;
            
            attrTypeNode = dsDataNodeAllocateString( 0, inAttributeName );
            status = dsGetRecordAttributeValueByIndex( recordRef, attrTypeNode, 1, &pExistingAttrValue );
            if ( status == eDSNoErr )
            {
				long valueLen = strlen(inValue);
                char *valueStr = (char *) malloc( valueLen + 1 );
                unsigned long attributeValueID = 1;
                
                strcpy( valueStr, inValue );
                if ( pExistingAttrValue ) {
                    attributeValueID = pExistingAttrValue->fAttributeValueID;
                }
                pNewAttrValue = dsAllocAttributeValueEntry(dsRef, attributeValueID, valueStr, valueLen );
                if ( pNewAttrValue == nil ) continue;
				
                status = dsSetAttributeValue(recordRef, attrTypeNode, pNewAttrValue);
				debugerr( status, "dsSetAttributeValue(#1) = %ld\n", status );
            }
            else
            if ( status == eDSAttributeNotFound || status == eDSAttributeDoesNotExist )
            {
                tDataNodePtr attrValue;
                
                attrValue = dsDataNodeAllocateString(dsRef, inValue);
                if ( attrValue ) {
                    status = dsAddAttribute( recordRef, attrTypeNode, NULL, attrValue );
					debugerr( status, "dsAddAttribute(#1) = %ld\n", status );
                }
            }
            // need to handle case of attribute with no values
				
            if (recordRef != 0) {
                dsCloseRecord( recordRef );
                recordRef = 0;
            }
			
			if ( inParentOnly )
				break;
        }
    }
    while( false );
    
    if (recordRef != 0) {
        dsCloseRecord( recordRef );
        recordRef = 0;
    }
	
	return status;
}


long SetPWConfigAttributeLDAP( const char *inRecordName, const char *inAttributeName, const char *inValue, const char *inUser, const char *inPassword, DSUtils *ldapNode )
{
    long						status				= eDSNoErr;
    tAttributeValueEntry	   *pExistingAttrValue	= NULL;
    tAttributeValueEntry	   *pNewAttrValue		= NULL;
	tRecordReference			recordRef			= 0;
    tDataNode				   *attrTypeNode		= nil;
	tDirReference				dsRef				= 0;
	
	if ( inUser != NULL && inPassword != NULL && ldapNode != NULL )
	{
		do
		{
			status = ldapNode->OpenLocalLDAPNode( inUser, inPassword );
			if ( status != eDSNoErr )
				break;
				
			status = ldapNode->OpenRecord( kDSStdRecordTypeConfig, inRecordName, &recordRef, true );
			if ( status != eDSNoErr )
				break;
			
			dsRef = ldapNode->GetDSRef();
			
			attrTypeNode = dsDataNodeAllocateString( 0, inAttributeName );
			status = dsGetRecordAttributeValueByIndex( recordRef, attrTypeNode, 1, &pExistingAttrValue );
			if ( status == eDSNoErr )
			{
				long valueLen = strlen(inValue);
				char *valueStr = (char *) malloc( valueLen + 1 );
				unsigned long attributeValueID = 1;
				
				strcpy( valueStr, inValue );
				if ( pExistingAttrValue ) {
					attributeValueID = pExistingAttrValue->fAttributeValueID;
				}
				pNewAttrValue = dsAllocAttributeValueEntry( dsRef, attributeValueID, valueStr, valueLen );
				if ( pNewAttrValue == nil ) break;
				
				status = dsSetAttributeValue( recordRef, attrTypeNode, pNewAttrValue );
				debugerr( status, "dsSetAttributeValue(#1.2) = %ld\n", status );
			}
			else
			if ( status == eDSAttributeNotFound || status == eDSAttributeDoesNotExist )
			{
				tDataNodePtr attrValue;
				
				attrValue = dsDataNodeAllocateString( dsRef, inValue );
				if ( attrValue ) {
					status = dsAddAttribute( recordRef, attrTypeNode, NULL, attrValue );
					debugerr( status, "dsAddAttribute(#1.2) = %ld\n", status );
				}
			}
			// need to handle case of attribute with no values
			else
			if ( status == eDSIndexOutOfRange )
			{
				tDataNodePtr attrValue;
				
				attrValue = dsDataNodeAllocateString( dsRef, inValue );
				if ( attrValue ) {
					status = dsAddAttributeValue( recordRef, attrTypeNode, attrValue );
					dsDataNodeDeAllocate( dsRef, attrValue );
					debugerr( status, "dsAddAttributeValue(#1.2) = %ld\n", status );
				}
			}
			
			if (recordRef != 0) {
				dsCloseRecord( recordRef );
				recordRef = 0;
			}
		}
		while( false );
		
		if (recordRef != 0) {
			dsCloseRecord( recordRef );
			recordRef = 0;
		}
	}
	
	return status;
}


// ---------------------------------------------------------------------------
//	* ProcessRunning
//
//  Returns: -1 = not running, or pid
// ---------------------------------------------------------------------------

pid_t ProcessRunning( const char *inProcName )
{
	register size_t		i ;
	register pid_t 		pidLast		= -1 ;
	int					mib[]		= { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
	size_t				ulSize		= 0;

	// Allocate space for complete process list
	if ( 0 > sysctl( mib, 4, NULL, &ulSize, NULL, 0) )
		return( pidLast );
	
	i = ulSize / sizeof( struct kinfo_proc );
	struct kinfo_proc	*kpspArray = new kinfo_proc[ i ];
	if ( !kpspArray )
		return( pidLast );
	
	// Get the proc list
	ulSize = i * sizeof( struct kinfo_proc );
	if ( 0 > sysctl( mib, 4, kpspArray, &ulSize, NULL, 0 ) )
	{
		delete [] kpspArray;
		return( pidLast );
	}

	register struct kinfo_proc	*kpsp = kpspArray;
	
	for ( ; i-- ; kpsp++ )
	{
		// match the name
		if ( strcmp( kpsp->kp_proc.p_comm, inProcName ) == 0 )
		{
			// skip zombies
			if ( kpsp->kp_proc.p_stat != SZOMB )
			{
				pidLast = kpsp->kp_proc.p_pid;
				continue;
			}
		}
	}
	
	delete [] kpspArray;
	
	return( pidLast );
}

// ---------------------------------------------------------------------------
//	* ProcessName
// ---------------------------------------------------------------------------

char *ProcessName( pid_t inPID )
{
	register size_t		i ;
	int					mib[]		= { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
	size_t				ulSize		= 0;
	char				*retVal		= NULL;
	
	// Allocate space for complete process list
	if ( 0 > sysctl( mib, 4, NULL, &ulSize, NULL, 0) )
		return NULL;
	
	i = ulSize / sizeof( struct kinfo_proc );
	struct kinfo_proc	*kpspArray = new kinfo_proc[ i ];
	if ( !kpspArray )
		return NULL;
	
	// Get the proc list
	ulSize = i * sizeof( struct kinfo_proc );
	if ( 0 > sysctl( mib, 4, kpspArray, &ulSize, NULL, 0 ) )
	{
		delete [] kpspArray;
		return NULL;
	}

	register struct kinfo_proc	*kpsp = kpspArray;
	
	for ( ; i-- ; kpsp++ )
	{
		// match the name
		if ( kpsp->kp_proc.p_pid == inPID )
		{			
			retVal = strdup( kpsp->kp_proc.p_comm );
			break;
		}
	}
	
	delete [] kpspArray;
	
	return retVal;
}