< Previous PageNext Page > Hide TOC

Working with Nodes

This chapter provides sample code that shows how to work with nodes. Finding a specific node, opening a session with the node, and authenticating a user to the node are fundamental Open Directory tasks.

In this section:

Listing Registered Nodes
Finding a Node
Opening and Closing a Node
Authenticating a User to a Node


Listing Registered Nodes

The sample code in Listing 2-1 demonstrates how to get a list of all registered nodes. The sample code opens an Open Directory session and gets an Open Directory reference. Then it calls its own ListNodes routine.

The ListNodes routine calls dsGetDirNodeCount to get the number of registered nodes. If the number of registered nodes is not zero, ListNodes calls dsDataBufferAllocate to allocate a data buffer and then calls dsGetDirNodeList to fill the buffer with the list of registered node names. The ListNodes routine then calls dsDataListAllocate to allocate a data list and dsGetDirNodeName to fill the data list with registered node names from the data buffer. The ListNodes routine then calls its own PrintNodeName routine to print the node names and passes to it a pointer to the data list.

The PrintNodeName routine calls dsGetPathFromList to get a node name from the data list and prints the name.

When the PrintNodeName routine returns, the ListNodes routine cleans up by calling dsDataListDeallocate and free() to deallocate the data list.

Listing 2-1  Listing registered nodes

tDirReference gDirRef = NULL;
void main ( )
{
    long dirStatus = eDSNoErr;
    dirStatus = dsOpenDirService( &gDirRef );
    if ( dirStatus == eDSNoErr )
    {
        ListNodes();
    }
    if ( gDirRef != NULL )
    {
        dirStatus = dsCloseDirService( gDirRef );
    }
}
void ListNodes ( void ) {
    bool done = false;
    long dirStatus = eDSNoErr;
    unsigned long index = 0;
    unsigned long nodeCount = 0;
    unsigned long bufferCount = 0;
    tDataBufferPtr dataBuffer = NULL;
    tDataListPtr nodeName = NULL;
    tContextData context = NULL;
 
    dirStatus = dsGetDirNodeCount( gDirRef, &nodeCount );
    printf( "Registered node count is: %lu\n", nodeCount  );
    if ( (dirStatus == eDSNoErr) && (nodeCount != 0) )
    {
        //Allocate a 32k buffer.
        dataBuffer = dsDataBufferAllocate( gDirRef, 32 * 1024 );
        if ( dataBuffer != NULL )
        {
            while ( (dirStatus == eDSNoErr) && (done ==  false) )
            {
                dirStatus = dsGetDirNodeList( gDirRef, dataBuffer,  &bufferCount,  &context );
                if ( dirStatus == eDSNoErr )
                {
                    for ( index = 1; index <= bufferCount; index++  )
                    {
                        dirStatus = dsGetDirNodeName( gDirRef, dataBuffer,  index,  &nodeName );
                        if ( dirStatus == eDSNoErr )
                        {
                            printf( "#%4ld ", index );
                            PrintNodeName( nodeName );
                            //Deallocate the data list containing  the node name.
                            dirStatus = dsDataListDeallocate( gDirRef,  nodeName );
                            free(nodeName);
                        }
                        else
                        {
                            printf("dsGetDirNodeName error  = %ld\n", dirStatus );
                        }
                    }
                }
                done = (context == NULL);
            }
            if (context != NULL)
            {
                dsReleaseContinueData( gDirRef, context );
            }
            dsDataBufferDeAllocate( gDirRef, dataBuffer );
            dataBuffer = NULL;
        }
    }
} // ListNodes
 
void PrintNodeName ( tDataListPtr inNode ) {
    char* pPath;
    pPath = dsGetPathFromList( gDirRef, inNode, "/" );
    printf( "%s\n", pPath );
    if ( pPath != NULL )
    {
        free( pPath );
        pPath = NULL;
    }
} // PrintNodeName

Finding a Node

The sample code in Listing 2-2 demonstrates how to find the node for a specific pathname. The sample code opens an Open Directory session and gets an Open Directory reference. Then it calls its own FindNodes routine and passes to it the pathname for the node that is to be found (/NetInfo/root).

The FindNodes routine calls dsBuildFromPath to build a data list for the pathname and calls dsDataBufferAllocate to allocate a data buffer in which to store the result of calling dsFindDirNodes. The routine then calls dsFindDirNodes to find the node whose name matches the specified pathname.

Then the FindNodes routine calls dsDataListAllocate to allocate a data list and provides that data list as a parameter when it calls dsGetDirNodeName. The dsGetDirNodeName function copies the node name from the data buffer filled in by dsFindDirNodes to the data list. Then the FindNodes routine calls its PrintNodeName routine to print the node name that was found. The PrintNodeName routine is described in the section Listing 2-1.

When the PrintNodeName routine returns, the FindNodes routine cleans up by calling dsDataListDeallocate and free() to deallocate the data list.

Listing 2-2  Finding the node for a pathname

void main ( )
{
    long dirStatus = eDSNoErr;
    dirStatus = dsOpenDirService( &gDirRef );
    if ( dirStatus == eDSNoErr )
    {
        FindNodes("/NetInfo/root");
    }
    if ( gDirRef != NULL )
    {
        dirStatus = dsCloseDirService( gDirRef );
    }
}
 
void FindNodes ( char* inNodePath ){
    bool done = false;
    long dirStatus = eDSNoErr;
    unsigned long index = 0;
    unsigned long bufferCount = 0;
    tDataBufferPtr dataBuffer = NULL;
    tDataListPtr nodeName = NULL;
    tContextData context = NULL;
    nodeName = dsBuildFromPath( gDirRef, inNodePath, "/");
    if ( nodeName != NULL )
    {
        //Allocate a 32k buffer.
        dataBuffer = dsDataBufferAllocate( gDirRef, 32 * 1024 );
        if ( dataBuffer != NULL )
        {
            while ( (dirStatus == eDSNoErr) && (done ==  false) )
            {
                dirStatus = dsFindDirNodes( gDirRef, dataBuffer,  nodeName,  eDSContains, &bufferCount, &context );
                if ( dirStatus == eDSNoErr )
                {
                    for ( index = 1; index <= bufferCount; index++  )
                    {
                        dirStatus = dsGetDirNodeName( gDirRef, dataBuffer,  index,  &nodeName );
                        if ( dirStatus == eDSNoErr )
                        {
                            printf( "#%4ld ", index );
                            PrintNodeName( nodeName );
                            //Deallocate the nodes.
                            dirStatus = dsDataListDeallocate( gDirRef,  nodeName );
                            free(nodeName);
                        }
                        else
                        {
                            printf("dsGetDirNodeName error  = %ld\n", dirStatus );
                        }
                    }
                }
                done = (context == NULL);
            }
            dirStatus = dsDataBufferDeAllocate( gDirRef, dataBuffer  );
            dataBuffer = NULL;
        }
    }
} // FindNodes

Opening and Closing a Node

The sample code in Listing 2-3 demonstrates how to open and close a node. The sample code opens an Open Directory session and gets an Open Directory reference. Then it calls its MyOpenDirNode routine and passes to it the address of the node reference (nodeRef) that it has allocated.

The MyOpenDirNode routine prints a prompt that solicits the entry of a node to open and calls scanf() to get the node’s name. It then calls dsBuildFromPath to build a data list containing the node name that was entered. It specifies the slash (/) character as the path delimiter. Then the MyOpenDirNode routine calls dsOpenDirNode to open the node. If the node can be opened, dsOpenDirNode stores in the node reference parameter a node reference that the application can use in subsequent calls to Open Directory functions that operate on the open node.

The MyOpenDirNode routine cleans up by calling dsCloseDirNode to close the node that was opened.

Listing 2-3  Opening a node

void main ( )
{
    long dirStatus = eDSNoErr;
    tDirNodeReference nodeRef = NULL;
    dirStatus = dsOpenDirService( &gDirRef );
    if ( dirStatus == eDSNoErr )
    {
        dirStatus = MyOpenDirNode( &nodeRef );
        if ( dirStatus == eDSNoErr )
        {
            dsCloseDirNode( nodeRef );
        }
    }
    if ( gDirRef != NULL )
    {
        dirStatus = dsCloseDirService( gDirRef );
    }
}
 
long MyOpenDirNode ( tDirNodeReference *outNodeRef )
{
    long dirStatus = eDSNoErr;
    char nodeName[ 256 ] = "\0";
    tDataListPtr nodePath = NULL;
    printf( "Open Node : " );
    fflush( stdout );
    scanf( "%s", nodeName );
    printf( "Opening: %s.\n", nodeName );
    nodePath = dsBuildFromPath( gDirRef, nodeName, "/"  );
    if ( nodePath != NULL )
    {
        dirStatus = dsOpenDirNode( gDirRef, nodePath, outNodeRef  );
        if ( dirStatus == eDSNoErr )
        {
            printf( "Open succeeded. Node Reference = %lu\n",  (unsigned  long)outNodeRef );
        }
        else
        {
            printf( "Open node failed. Err = %ld\n", dirStatus  );
        }
    }
    dsDataListDeallocate( gDirRef, nodePath );
    free( nodePath );
    return( dirStatus );
} // MyOpenDirNode

Authenticating a User to a Node

To authenticate itself to the Open Directory for the purposes of reading, writing, or making changes to a node, an Open Directory client application calls dsDoDirNodeAuth. The dsDoDirNodeAuth function handles authentication methods that use one or more steps to complete the authentication process.

To determine the authentication methods that a node supports, call dsGetDirNodeInfo for the node and request the kDSNAttrAuthMethod attribute. For any particular user, some methods may not be supported. The available authentication methods depend on the authentication authority of the user that is being authenticated.

If the authentication methods that an authentication authority implements are known, the authentication authority may be used to deduce those authentication methods that are available for a user. Note, however, that it is possible to disable hash storage on a per-user basis, which has the effect of disabling some authentication methods that would otherwise be available.

Directory Native Authentication

The sample code Listing 2-4 demonstrates directory native authentication. In the sample code, the inDirNodeRef parameter contains a node reference for the node, inUserName parameter contains the user name that is to be authenticated to the node, the inUserPassword contains the password in cleartext that is to be used to authenticate the user name.

Listing 2-4  Authenticating using directory native authentication

Bool DoNodeNativeAuthentication ( const tDirReference inDirRef,
                            const tDirNodeReference inDirNodeRef,
                            const char *inUserName,
                            const char *inUserPassword )
{
    //  Native authentication is a one step authentication scheme.
    //  Step 1
    //      Send: <length><recordname>
    //            <length><cleartextpassword>
    //   Receive: success or failure.
 
    tDataNodePtr anAuthType2Use = NULL;
    tDataBufferPtr anAuthDataBuf = NULL;
    tDataBufferPtr aAuthRespBuf = NULL;
    tDirStatus aDirErr = eDSNoErr;
    tContextData aContinueData = NULL;
    long aDataBufSize = 0;
    long aTempLength = 0;
    long aCurLength = 0;
    bool aResult = false;
    // First, specify the type of authentication.
    anAuthType2Use =  dsDataNodeAllocateString(inDirRef,kDSStdAuthNodeNativeClearTextOK);
    // The following is an optional method of authentication that  allows the
    // plug-in to choose the authentication method, but the client  can
    // “restrict” the authentication request to be "secure"  and not use
    // cleartext. Both authentication methods take the same buffer  arguments.
    /* anAuthType2Use = dsDataNodeAllocate(inDirRef,  kDSStdAuthNodeNativeNoClearText); */
    aDataBufSize += sizeof(long) + ::strlen(inUserName);
    aDataBufSize += sizeof(long) + ::strlen(inUserPassword);
    anAuthDataBuf = dsDataBufferAllocate(inDirRef, aDataBufSize);
    aAuthRespBuf = dsDataBufferAllocate(inDirRef, 512); // For the  response.
    // Put all of the authentication arguments into the data buffer.
    aTempLength = ::strlen(inUserName);
    ::memcpy(&(anAuthDataBuf->fBufferData[aCurLength]), &aTempLength,  sizeof(long));
    aCurLength += sizeof(long);
    ::memcpy(&(anAuthDataBuf->fBufferData[aCurLength]), inUserName,  aTempLength);
    aCurLength += aTempLength;
    aTempLength = ::strlen(inUserPassword);
    ::memcpy(&(anAuthDataBuf->fBufferData[aCurLength]), &aTempLength,  sizeof(long));
    aCurLength += sizeof(long);
    ::memcpy(&(anAuthDataBuf->fBufferData[aCurLength]), inUserPassword,  aTempLength);
    aCurLength += aTempLength;
 
    anAuthBuff->fBufferLength = aDataBufSize;
    aDirErr = dsDoDirNodeAuth(inDirNodeRef, anAuthType2Use, true,  anAuthDataBuf,  aAuthRespBuf, &aContinueData);
    switch(aDirErr)
    {
        case eDSNoErr:
            aResult = true;
            break;
        default:
            // If any other error, assume the name or password is  bad.
            aResult = false;
            break;
    }
    // Clean up allocations.
    aDirErr = dsDataBufferDeAllocate(inDirRef, anAuthDataBuf);
    anAuthDataBuf = NULL;
    // Don't need to keep the response.
    aDirErr = dsDataBufferDeAllocate(inDirRef, aAuthRespBuf);
    aAuthRespBuf = NULL;
    // Don't need the authentication type value. Build a new one  if needed
    // later.
    aDirErr = dsDataNodeDeAllocate(inDirRef, anAuthType2Use);
    anAuthType2Use = NULL;
    // Return the result of the authentication.
    return (aResult);
}


< Previous PageNext Page > Hide TOC


© 2007 Apple Inc. All Rights Reserved. (Last updated: 2007-01-08)


Did this document help you?
Yes: Tell us what works for you.
It’s good, but: Report typos, inaccuracies, and so forth.
It wasn’t helpful: Tell us what would have helped.