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.
Listing Registered Nodes
Finding a Node
Opening and Closing a Node
Authenticating a User to a Node
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 |
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 |
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 |
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.
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); |
} |
© 2007 Apple Inc. All Rights Reserved. (Last updated: 2007-01-08)