DSUtils.mm   [plain text]


/*
 *  DirServiceUtils.cpp
 *  NeST
 *
 *  Created by admin on Fri Apr 04 2003.
 *  Copyright (c) 2003 __MyCompanyName__. All rights reserved.
 *
 */

#include <stdio.h>

#include "DSUtils.h"

DSUtils::DSUtils()
{
	mDSRef = 0;
	mNodeRef = 0;
	mNodeListBuff = NULL;
	mNodeCount = 0;
	mCurrentNodeAuthenticated = false;
	mCurrentNodeIsLDAP = false;
}


DSUtils::~DSUtils()
{
	if ( mNodeListBuff != NULL )
	{
		dsDataBufferDeAllocate( mDSRef, mNodeListBuff );
		mNodeListBuff = NULL;
	}
	
	this->CloseCurrentNodeRef();
	if ( mDSRef != 0 )
	{
		dsCloseDirService( mDSRef );
		mDSRef = 0;
	}
}


void
DSUtils::CloseCurrentNodeRef( void )
{
	if ( mNodeRef != 0 )
	{
		dsCloseDirNode( mNodeRef );
		mNodeRef = 0;
		mCurrentNodeAuthenticated = false;
		mCurrentNodeIsLDAP = false;
	}
}


tDirStatus
DSUtils::OpenDirectoryServices( void )
{
	tDirStatus status = eDSNoErr;
	
	if ( mDSRef == 0 )
		status = dsOpenDirService( &mDSRef );
	
	return status;
}


//-----------------------------------------------------------------------------
//	OpenSpecificPasswordServerNode
//
//	RETURNS: tDirStatus
//-----------------------------------------------------------------------------

tDirStatus
DSUtils::OpenSpecificPasswordServerNode( const char *inServerAddress )
{
	char pwServerNodeStr[256];
    tDataList *pDataList = nil;
	tDirStatus status = eDSNoErr;
	
	if ( inServerAddress == NULL )
		return eParameterError;
	
	status = this->OpenDirectoryServices();
	if ( status != eDSNoErr )
		return status;
	
	this->CloseCurrentNodeRef();
	
	strcpy( pwServerNodeStr, "/PasswordServer/only/" );
	strcat( pwServerNodeStr, inServerAddress );
    
	pDataList = dsBuildFromPath( mDSRef, pwServerNodeStr, "/" );
	status = dsOpenDirNode( mDSRef, pDataList, &mNodeRef );
	dsDataListDeallocate( mDSRef, pDataList );
	free( pDataList );

	return status;
}


//-----------------------------------------------------------------------------
//	OpenLocalLDAPNode
//
//	RETURNS: tDirStatus
//-----------------------------------------------------------------------------

tDirStatus
DSUtils::OpenLocalLDAPNode( const char *inUser, const char *inPassword )
{
    tDirStatus					status				= eDSNoErr;
    tContextData				context				= NULL;
    tDataListPtr				patternList			= NULL;
	tDataBufferPtr				authBuff			= NULL;
	tDataBufferPtr				authStepBuff		= NULL;
	tContextData				continueData		= NULL;
	tDataNodePtr				typeBuff			= NULL;
	long						len					= 0;
	
	if ( mCurrentNodeIsLDAP && mCurrentNodeAuthenticated )
		return eDSNoErr;
	
	status = this->OpenDirectoryServices();
	if ( status != eDSNoErr )
		return status;
	
	if ( mNodeListBuff == NULL )
	{
		mNodeListBuff = dsDataBufferAllocate( mDSRef, 4096 );
		if ( mNodeListBuff == NULL )
			return eMemoryError;
	}
	else
	{
		mNodeListBuff->fBufferLength = 0;
	}
	
	// find and don't open
	
	patternList = dsBuildFromPath( mDSRef, "/LDAPv3/127.0.0.1", "/" );
	if ( patternList == NULL )
		return eMemoryError;
	
	status = dsFindDirNodes( mDSRef, mNodeListBuff, patternList, eDSExact, &mNodeCount, &context );
	if ( status != eDSNoErr )
		return status;
	
	if ( mNodeCount < 1 )
		return eDSNodeNotFound;
	
	status = this->OpenLocallyHostedNode( 1 );
	if ( status != eDSNoErr )
		return status;
	
	mCurrentNodeIsLDAP = true;
	
	if ( inUser != NULL && inPassword != NULL )
	{
		authBuff = dsDataBufferAllocate( mDSRef, 4096 );
		if ( authBuff == NULL )
			return eMemoryError;
		
		authStepBuff = dsDataBufferAllocate( mDSRef, 2048 );
		if ( authStepBuff == NULL )
			return eMemoryError;
		
		typeBuff = dsDataNodeAllocateString( mDSRef, kDSStdAuthNodeNativeClearTextOK );
		if ( typeBuff == NULL )
			return eMemoryError;
		
		len = strlen( inUser );
		memcpy( authBuff->fBufferData, &len, 4 );
		strcpy( authBuff->fBufferData + 4, inUser );
		authBuff->fBufferLength = 4 + len;
		
		len = strlen( inPassword );
		memcpy( authBuff->fBufferData + authBuff->fBufferLength, &len, 4 );
		strcpy( authBuff->fBufferData + authBuff->fBufferLength + 4, inPassword );
		authBuff->fBufferLength += 4 + len;
		
		status = dsDoDirNodeAuth( this->GetCurrentNodeRef(), typeBuff, false, authBuff, authStepBuff, &continueData );
		if ( status == eDSNoErr )
			mCurrentNodeAuthenticated = true;
	}
	
	return status;
}


//-----------------------------------------------------------------------------
//	OpenNodeByName
//
//	RETURNS: tDirStatus
//-----------------------------------------------------------------------------

tDirStatus
DSUtils::OpenNodeByName( const char *inNodeName, const char *inUser, const char *inPassword )
{
    tDirStatus					status				= eDSNoErr;
    tDataListPtr				nodeName			= NULL;
	tDataBufferPtr				authBuff			= NULL;
	tDataBufferPtr				authStepBuff		= NULL;
	tContextData				continueData		= NULL;
	tDataNodePtr				typeBuff			= NULL;
	long						len					= 0;
	
	if ( inNodeName == NULL )
		return eParameterError;
	
	status = this->OpenDirectoryServices();
	if ( status != eDSNoErr )
		return status;
	
	if ( mNodeListBuff == NULL )
	{
		mNodeListBuff = dsDataBufferAllocate( mDSRef, 4096 );
		if ( mNodeListBuff == NULL )
			return eMemoryError;
	}
	else
	{
		mNodeListBuff->fBufferLength = 0;
	}
	
	// find and don't open
	
	nodeName = dsBuildFromPath( mDSRef, inNodeName, "/" );
	if ( nodeName == NULL )
		return eMemoryError;
		
	status = dsOpenDirNode( mDSRef, nodeName, &mNodeRef );
	dsDataListDeallocate( mDSRef, nodeName );
	free( nodeName );
	if ( status != eDSNoErr )
		return status;
	
	if ( inUser != NULL && inPassword != NULL )
	{
		authBuff = dsDataBufferAllocate( mDSRef, 4096 );
		if ( authBuff == NULL )
			return eMemoryError;
		
		authStepBuff = dsDataBufferAllocate( mDSRef, 2048 );
		if ( authStepBuff == NULL )
			return eMemoryError;
		
		typeBuff = dsDataNodeAllocateString( mDSRef, kDSStdAuthNodeNativeClearTextOK );
		if ( typeBuff == NULL )
			return eMemoryError;
		
		len = strlen( inUser );
		memcpy( authBuff->fBufferData, &len, 4 );
		strcpy( authBuff->fBufferData + 4, inUser );
		authBuff->fBufferLength = 4 + len;
		
		len = strlen( inPassword );
		memcpy( authBuff->fBufferData + authBuff->fBufferLength, &len, 4 );
		strcpy( authBuff->fBufferData + authBuff->fBufferLength + 4, inPassword );
		authBuff->fBufferLength += 4 + len;
		
		status = dsDoDirNodeAuth( this->GetCurrentNodeRef(), typeBuff, false, authBuff, authStepBuff, &continueData );
		if ( status == eDSNoErr )
			mCurrentNodeAuthenticated = true;
	}
	
	return status;	
}


//-----------------------------------------------------------------------------
//	OpenNetInfoParentNode
//
//	RETURNS: tDirStatus
//
//	Opens the NetInfo parent node if the local machine is hosting one.
//-----------------------------------------------------------------------------

tDirStatus
DSUtils::OpenNetInfoParentNode( void )
{
    tDirStatus					status				= eDSNoErr;
	tDataList					*pDataList			= NULL;
    
	status = this->OpenDirectoryServices();
	if ( status != eDSNoErr )
		return status;
	
	if ( mNodeListBuff == NULL )
	{
		mNodeListBuff = dsDataBufferAllocate( mDSRef, 4096 );
		if ( mNodeListBuff == NULL )
			return eMemoryError;
	}
	else
	{
		mNodeListBuff->fBufferLength = 0;
	}

	pDataList = dsBuildFromPath( mDSRef, "/NetInfo/..", "/" );
	status = dsOpenDirNode( mDSRef, pDataList, &mNodeRef );
	dsDataListDeallocate( mDSRef, pDataList );
	free( pDataList );
	
	return status;
}


//-----------------------------------------------------------------------------
//	GetLocallyHostedNodeList
//
//	RETURNS: tDirStatus
//-----------------------------------------------------------------------------

tDirStatus
DSUtils::GetLocallyHostedNodeList( void )
{
    tDirStatus					status				= eDSNoErr;
    tContextData				context				= NULL;
    
	status = this->OpenDirectoryServices();
	if ( status != eDSNoErr )
		return status;
	
	if ( mNodeListBuff == NULL )
	{
		mNodeListBuff = dsDataBufferAllocate( mDSRef, 4096 );
		if ( mNodeListBuff == NULL )
			return eMemoryError;
	}
	
	// find and don't open
	status = dsFindDirNodes( mDSRef, mNodeListBuff, NULL, eDSLocalHostedNodes, &mNodeCount, &context );
	if ( status != eDSNoErr )
		return status;
	
	if ( mNodeCount < 1 )
		status = eDSNodeNotFound;
	
	return status;
}


tDirStatus
DSUtils::OpenLocallyHostedNode( unsigned long inNodeIndex )
{
    tDirStatus			status				= eDSNoErr;
    tDataList			*nodeName			= NULL;
        
	// make sure the state is correct
	if ( mDSRef == 0 || mNodeListBuff == NULL || inNodeIndex > mNodeCount )
		return eParameterError;
	
	this->CloseCurrentNodeRef();
	
	status = dsGetDirNodeName( mDSRef, mNodeListBuff, inNodeIndex, &nodeName );
	if ( status != eDSNoErr )
		return status;
	
	status = dsOpenDirNode( mDSRef, nodeName, &mNodeRef );
	dsDataListDeallocate( mDSRef, nodeName );
	free( nodeName );
                        
	return status;
}


tDirStatus
DSUtils::OpenRecord(
	const char *inRecordType,
	const char *inRecordName,
	tRecordReference *outRecordRef,
	bool inCreate )
{
    tDirStatus				status				= eDSNoErr;
    tDataNodePtr			recordTypeNode		= NULL;
    tDataNodePtr			recordNameNode		= NULL;    

	// make sure the state is correct
	if ( mDSRef == 0 || mNodeRef == 0 || inRecordType == NULL || inRecordName == NULL || outRecordRef == NULL )
		return eParameterError;
	
	recordTypeNode = dsDataNodeAllocateString( mDSRef, inRecordType );
	recordNameNode = dsDataNodeAllocateString( mDSRef, inRecordName );
	
	status = dsOpenRecord( mNodeRef, recordTypeNode, recordNameNode, outRecordRef );
	
	if ( inCreate && status == eDSRecordNotFound )
		status = dsCreateRecordAndOpen( mNodeRef, recordTypeNode, recordNameNode, outRecordRef );
	
	if ( recordTypeNode ) {
		dsDataNodeDeAllocate( mDSRef, recordTypeNode );
		recordTypeNode = NULL;
	}
	if ( recordNameNode ) {
		dsDataNodeDeAllocate( mDSRef, recordNameNode );
		recordNameNode = NULL;
	}
	
	return status;
}


//--------------------------------------------------------------------------------------------------
// * DoActionOnCurrentNode ()
//--------------------------------------------------------------------------------------------------

tDirStatus
DSUtils::DoActionOnCurrentNode( void )
{
	fprintf( stderr, "warning: DSUtils::DoActionOnCurrentNode() called, does not perform any action." );
	return (tDirStatus)0;
}


//--------------------------------------------------------------------------------------------------
// * DoActionForAllLocalNodes ()
//
//  Returns: the first error encountered
//--------------------------------------------------------------------------------------------------

tDirStatus
DSUtils::DoActionForAllLocalNodes( void )
{
    tDirStatus					status				= eDSNoErr;
    tDirStatus					status1				= eDSNoErr;
    unsigned long				index				= 0;
    unsigned long				nodeCount			= 0;
	
	status = this->GetLocallyHostedNodeList();
	if ( status != eDSNoErr )
		return status;
	
	nodeCount = this->GetLocallyHostedNodeCount();
	for ( index = 1; index <= nodeCount; index++ )
	{
		status1 = this->OpenLocallyHostedNode( index );
		if ( status1 != eDSNoErr )
		{
			if ( status == eDSNoErr )
				status = status1;
			continue;
		}
		
		status1 = this->DoActionOnCurrentNode();
		if ( status1 != eDSNoErr && status == eDSNoErr )
			status = status1;
	}
	
	return status;
}


//--------------------------------------------------------------------------------------------------
// * FillAuthBuff ()
//
//		inCount		== Number of uInt32, void* pairs
//		va args		== uInt32, void* pairs
//--------------------------------------------------------------------------------------------------

tDirStatus
DSUtils::FillAuthBuff( tDataBuffer *inAuthBuff, unsigned long inCount, unsigned long inLen, ... )
{
	tDirStatus			error		= eDSNoErr;
	unsigned long		curr		= 0;
	unsigned long		buffSize	= 0;
	unsigned long		count		= inCount;
	unsigned long		len			= inLen;
	const void	 		*data		= NULL;
	bool		firstPass	= true;
	char	   *p			= nil;
	va_list		args;

	// If the buffer is nil, we have nowhere to put the data
	if ( inAuthBuff == nil )
		return eParameterError;
	
	// If the buffer is nil, we have nowhere to put the data
	if ( inAuthBuff->fBufferData == nil )
	{
		return( eDSEmptyBuffer );
	}
	
	// Get buffer info
	p		 = inAuthBuff->fBufferData;
	buffSize = inAuthBuff->fBufferSize;
	
	// Set up the arg list
	va_start( args, inLen );
	data = va_arg( args, void * );
	
	while ( count-- > 0 )
	{
		if ( !firstPass )
		{
			len = va_arg( args, unsigned long );
			data = va_arg( args, void * );
		}
		
		if ( (curr + len) > buffSize )
		{
			// This is bad, lets bail
			return( eDSBufferTooSmall );
		}
		
		::memcpy( &(p[ curr ]), &len, sizeof( long ) );
		curr += sizeof( long );

		if ( len > 0 )
		{
			memcpy( &(p[ curr ]), data, len );
			curr += len;
		}
		firstPass = false;
	}

	inAuthBuff->fBufferLength = curr;

	return( error );

} // FillAuthBuff


//-------------------------------------------------------------------------------------
//	GetServerAddressForUser
//-------------------------------------------------------------------------------------

tDirStatus
DSUtils::GetServerAddressForUser( const char *uname, char *serverAddress, char **userNodeName )
{
    tDataBuffer				   *tDataBuff			= NULL;
    tDirNodeReference			nodeRef				= 0;
    tDirStatus					status				= eDSNoErr;
    tContextData				context				= NULL;
	unsigned long				nodeCount			= 0;
	unsigned long				attrIndex			= 0;
	tDataList				   *nodeName			= NULL;
    tAttributeEntryPtr			pAttrEntry			= NULL;
	tDataList				   *pRecName			= NULL;
	tDataList				   *pRecType			= NULL;
	tDataList				   *pAttrType			= NULL;
	unsigned long				recCount			= 0;
	tRecordEntry		  	 	*pRecEntry			= NULL;
	tAttributeListRef			attrListRef			= 0;
	char					   *pUserLocation		= NULL;
	tAttributeValueListRef		valueRef			= 0;
	tAttributeValueEntry  	 	*pValueEntry		= NULL;
	tDataList				   *pUserNode			= NULL;
	tDirNodeReference			userNodeRef			= 0;
	
	if ( uname == NULL )
		return eDSAuthUnknownUser;
	
	if ( userNodeName != NULL )
		*userNodeName = NULL;
	
	try
    {
		status = this->OpenDirectoryServices();
		if ( status != eDSNoErr )
			throw( status );
		
		tDataBuff = dsDataBufferAllocate( mDSRef, 4096 );
		if (tDataBuff == NULL)
			throw( (tDirStatus)eMemoryError );
        
		// find on search node
		status = dsFindDirNodes( mDSRef, tDataBuff, NULL, eDSSearchNodeName, &nodeCount, &context );
		if (status != eDSNoErr)
			throw( status );
		if ( nodeCount < 1 )
			throw( (tDirStatus)eDSNodeNotFound );
		
		status = dsGetDirNodeName( mDSRef, tDataBuff, 1, &nodeName );
		if (status != eDSNoErr)
			throw( status );
		
		status = dsOpenDirNode( mDSRef, nodeName, &nodeRef );
		dsDataListDeallocate( mDSRef, nodeName );
		free( nodeName );
		nodeName = NULL;
		if (status != eDSNoErr)
			throw( status );
		
		pRecName = dsBuildListFromStrings( mDSRef, uname, NULL );
		pRecType = dsBuildListFromStrings( mDSRef, kDSStdRecordTypeUsers, NULL );
		pAttrType = dsBuildListFromStrings( mDSRef, kDSNAttrMetaNodeLocation, NULL );
		
		recCount = 1;
		status = dsGetRecordList( nodeRef, tDataBuff, pRecName, eDSExact, pRecType, pAttrType, 0, &recCount, &context );
		if ( status != eDSNoErr )
			throw( status );
		if ( recCount == 0 )
			throw( (tDirStatus)eDSAuthUnknownUser );
		
		status = dsGetRecordEntry( nodeRef, tDataBuff, 1, &attrListRef, &pRecEntry );
		if ( status != eDSNoErr )
			throw( status );
		
		for ( attrIndex = 1; (attrIndex <= pRecEntry->fRecordAttributeCount) && (status == eDSNoErr); attrIndex++ )
		{
			status = dsGetAttributeEntry( nodeRef, tDataBuff, attrListRef, attrIndex, &valueRef, &pAttrEntry );
			if ( status == eDSNoErr && pAttrEntry != NULL )
			{
				if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrMetaNodeLocation ) == 0 )
				{
					status = dsGetAttributeValue( nodeRef, tDataBuff, 1, valueRef, &pValueEntry );
					if ( status == eDSNoErr && pValueEntry != NULL )
					{
						pUserLocation = (char *) calloc( pValueEntry->fAttributeValueData.fBufferLength + 1, sizeof(char) );
						memcpy( pUserLocation, pValueEntry->fAttributeValueData.fBufferData, pValueEntry->fAttributeValueData.fBufferLength );
					}
				}
				
				if ( pValueEntry != NULL )
					dsDeallocAttributeValueEntry( mDSRef, pValueEntry );
				pValueEntry = NULL;
				
				dsDeallocAttributeEntry( mDSRef, pAttrEntry );
				pAttrEntry = NULL;
				dsCloseAttributeValueList( valueRef );
				valueRef = 0;
			}
		}
		
		dsCloseAttributeList( attrListRef );
		attrListRef = 0;
		dsDeallocRecordEntry( mDSRef, pRecEntry );
		pRecEntry = NULL;
		
		if ( pUserLocation == NULL )
			throw( (tDirStatus)eDSAuthUnknownUser );
		
		
		pUserNode = dsBuildFromPath( mDSRef, pUserLocation, "/" );
		status = dsOpenDirNode( mDSRef, pUserNode, &userNodeRef );
		if ( status != eDSNoErr )
			throw( status );
		
		// assign after we know we can open the node
		if ( userNodeName != NULL )
			*userNodeName = pUserLocation;
		
		// now, get the config record
		if (pRecName != NULL) {
			dsDataListDeallocate( mDSRef, pRecName );
			free( pRecName );
			pRecName = NULL;
		}
		if (pRecType != NULL) {
			dsDataListDeallocate( mDSRef, pRecType );
			free( pRecType );
			pRecType = NULL;
		}
		if (pAttrType != NULL) {
			dsDataListDeallocate( mDSRef, pAttrType );
			free( pAttrType );
			pAttrType = NULL;
		}
		
		pRecName = dsBuildListFromStrings( mDSRef, "passwordserver", NULL );
		pRecType = dsBuildListFromStrings( mDSRef, kDSStdRecordTypeConfig, NULL );
		pAttrType = dsBuildListFromStrings( mDSRef, kDS1AttrPasswordServerLocation, NULL );
		
		recCount = 1;
		status = dsGetRecordList( nodeRef, tDataBuff, pRecName, eDSExact, pRecType, pAttrType, 0, &recCount, &context );
		if ( status != eDSNoErr )
			throw( status );
		if ( recCount == 0 )
			throw( (tDirStatus)eDSRecordNotFound );
		
		status = dsGetRecordEntry( nodeRef, tDataBuff, 1, &attrListRef, &pRecEntry );
		if ( status != eDSNoErr )
			throw( status );
		
		for ( attrIndex = 1; (attrIndex <= pRecEntry->fRecordAttributeCount) && (status == eDSNoErr); attrIndex++ )
		{
			status = dsGetAttributeEntry( nodeRef, tDataBuff, attrListRef, attrIndex, &valueRef, &pAttrEntry );
			if ( status == eDSNoErr && pAttrEntry != NULL )
			{
				if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDS1AttrPasswordServerLocation ) == 0 )
				{
					status = dsGetAttributeValue( nodeRef, tDataBuff, 1, valueRef, &pValueEntry );
					if ( status == eDSNoErr && pValueEntry != NULL )
					{
						memcpy( serverAddress, pValueEntry->fAttributeValueData.fBufferData, pValueEntry->fAttributeValueData.fBufferLength );
						serverAddress[pValueEntry->fAttributeValueData.fBufferLength] = '\0';
					}
				}
				
				if ( pValueEntry != NULL )
					dsDeallocAttributeValueEntry( mDSRef, pValueEntry );
				pValueEntry = NULL;
				
				dsDeallocAttributeEntry( mDSRef, pAttrEntry );
				pAttrEntry = NULL;
				dsCloseAttributeValueList( valueRef );
				valueRef = 0;
			}
		}
	}
	catch ( tDirStatus catchErr )
	{
		status = catchErr;
	}
	
	if ( attrListRef != 0 ) {
		dsCloseAttributeList( attrListRef );
		attrListRef = 0;
	}
	if ( pRecEntry != NULL ) {
		dsDeallocRecordEntry( mDSRef, pRecEntry );
		pRecEntry = NULL;
	}
	
    if (tDataBuff != NULL) {
		bzero( tDataBuff, tDataBuff->fBufferSize );
		dsDataBufferDeAllocate( mDSRef, tDataBuff );
		tDataBuff = NULL;
	}
	
	if (pUserLocation != NULL && userNodeName == NULL ) {
		free( pUserLocation );
		pUserLocation = NULL;
	}
	if (pRecName != NULL) {
		dsDataListDeallocate( mDSRef, pRecName );
		free( pRecName );
		pRecName = NULL;
	}
	if (pRecType != NULL) {
		dsDataListDeallocate( mDSRef, pRecType );
		free( pRecType );
		pRecType = NULL;
	}
	if (pAttrType != NULL) {
		dsDataListDeallocate( mDSRef, pAttrType );
		free( pAttrType );
		pAttrType = NULL;
	}
    if (nodeRef != 0) {
		dsCloseDirNode(nodeRef);
		nodeRef = 0;
	}
	
	return status;
}