#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <readpassphrase.h>
#include <DirectoryService/DirectoryService.h>
#ifndef bool
typedef enum { false = 0, true = 1 } bool;
#endif /* bool */
// 32k buffer
#define BUFFERSIZE 32 * 1024
tDirReference DoNTLMv2Auth(
tDirReference dirRef,
tDirNodeReference nodeRef,
const char *user,
const char *challange,
long challangeLen,
const char *response,
long responseLen,
const char *domain,
bool *authResult,
char **resultMsg )
{
long dirStatus = eDSNoErr ;
tDataBufferPtr authBuffer ;
tDataBufferPtr respBuffer ;
tContextData authContext = NULL ;
tDataNodePtr authType ;
long userLen = strlen( user );
long domainLen = strlen( domain );
long authBufferLen ;
authBufferLen = sizeof(long) + userLen
+ sizeof(long) + challangeLen
+ sizeof(long) + responseLen
+ sizeof(long) + userLen
+ sizeof(long) + domainLen ;
authBuffer = dsDataBufferAllocate( dirRef, authBufferLen );
respBuffer = dsDataBufferAllocate( dirRef, BUFFERSIZE );
#if ( MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 )
// Leopard
dsFillAuthBuffer( authBuffer, 5,
userLen, user,
challangeLen, challange,
responseLen, response,
userLen, user,
domainLen, domain );
#else // tiger or earier
long pos = 0;
// user name
memcpy( &(authBuffer->fBufferData[pos]), &userLen, sizeof(long) );
pos += sizeof(long);
memcpy( &(authBuffer->fBufferData[pos]), user, userLen );
pos += userLen ;
// server challange
memcpy( &(authBuffer->fBufferData[pos]), &challangeLen, sizeof(long) );
pos += sizeof(long);
memcpy( &(authBuffer->fBufferData[pos]), challange, challangeLen );
pos += challangeLen ;
// client response ( response + client blob )
memcpy( &(authBuffer->fBufferData[pos]), &responseLen, sizeof(long) );
pos += sizeof(long);
memcpy( &(authBuffer->fBufferData[pos]), response, responseLen );
pos += responseLen ;
// samba user name
memcpy( &(authBuffer->fBufferData[pos]), &userLen, sizeof(long) );
pos += sizeof(long);
memcpy( &(authBuffer->fBufferData[pos]), user, userLen );
pos += userLen ;
// samba domain
memcpy( &(authBuffer->fBufferData[pos]), &domainLen, sizeof(long) );
pos += sizeof(long);
memcpy( &(authBuffer->fBufferData[pos]), domain, domainLen );
pos += domainLen ;
authBuffer->fBufferLength = pos ;
#endif
authType = dsDataNodeAllocateString( dirRef, kDSStdAuthNTLMv2 );
dirStatus = dsDoDirNodeAuth( nodeRef, authType, true, authBuffer, respBuffer, &authContext );
switch( dirStatus )
{
case eDSNoErr: // Auth Success
*authResult = true ;
if( resultMsg ) *resultMsg = "Auth Success." ;
break;
case eDSAuthFailed : // Auth Fail
*authResult = false ;
if( resultMsg ) *resultMsg = "Auth Failure." ;
break;
case eDSAuthMethodNotSupported : // Auth not supported
*authResult = false ;
if( resultMsg ) *resultMsg = "This Auth Type not supported." ;
break;
default:
*authResult = false ;
if( resultMsg ) *resultMsg = "unknown error." ;
break;
}
dsDataBufferDeAllocate ( dirRef, authBuffer );
dsDataBufferDeAllocate ( dirRef, respBuffer );
return dirStatus;
}
int main( int argc, char *argv[] )
{
int ret = 0 ;
long dirStatus = eDSNoErr ;
tDirReference dirRef = 0 ;
tDirNodeReference nodeRef = 0 ;
const char *nodepath = (argc > 1 ? argv[1] : "/Local/Default" );
tDataListPtr nodeName = NULL ;
const char *user = (argc > 2 ? argv[2] : "me" );
char pass[BUFFERSIZE] ; // tenuki
const char *domain = (argc > 3 ? argv[3] : "WORKGROUP" );
const char challange[] = { 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 } ; // 8byte challange
const char blob[] = { 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // signature & reserved
0x00, 0x90, 0xd3, 0x36, 0xb7, 0x34, 0xc3, 0x01, // timestamp
0xff, 0xff, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, // client once
0x00, 0x00, 0x00, 0x00, // unknown 1
0x02, 0x00, 0x0c, 0x00, 0x44, 0x00, 0x4f, 0x00, // target information
0x4d, 0x00, 0x41, 0x00, 0x49, 0x00, 0x4e, 0x00,
0x01, 0x00, 0x0c, 0x00, 0x53, 0x00, 0x45, 0x00,
0x52, 0x00, 0x56, 0x00, 0x45, 0x00, 0x52, 0x00,
0x04, 0x00, 0x14, 0x00, 0x64, 0x00, 0x6f, 0x00,
0x6d, 0x00, 0x61, 0x00, 0x69, 0x00, 0x6e, 0x00,
0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00,
0x03, 0x00, 0x22, 0x00, 0x73, 0x00, 0x65, 0x00,
0x72, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00,
0x2e, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x6d, 0x00,
0x61, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x2e, 0x00,
0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00 // unknown 2
};
char response[16 + sizeof( blob ) ] ; // response
char *resultMsg = NULL ;
bool isAuthOK = false;
// open OD
dirStatus = dsOpenDirService( &dirRef );
if( dirStatus != eDSNoErr ) goto errexit ;
// open node
nodeName = dsBuildFromPath( dirRef, nodepath, "/" );
if( nodeName == NULL )
{
fprintf( stderr, "name buffer allocate error\n") ;
ret = 1;
goto toexit;
}
dirStatus = dsOpenDirNode( dirRef, nodeName, &nodeRef );
if( dirStatus != eDSNoErr ) goto errexit ;
if( NULL == readpassphrase("Passwd: ", pass, sizeof( pass ), 0 ) )
goto errexit ;
makeNTLMv2Resnpose( user, pass, challange, sizeof(challange), blob, sizeof(blob), domain, response );
dirStatus = DoNTLMv2Auth( dirRef,
nodeRef,
user,
challange, sizeof(challange),
response, sizeof(response),
domain,
&isAuthOK,
&resultMsg );
printf( "user %s, auth %s.\n", user, ( isAuthOK ? "OK" : "NG" ) );
if( resultMsg != NULL )
printf( "msg = %s\n", resultMsg );
goto toexit;
errexit:
ret = 1;
fprintf( stderr, "errocode = %d\n", dirStatus );
toexit:
if( nodeRef != 0 )
dsCloseDirNode( nodeRef );
if( dirRef != 0 )
dsCloseDirService( dirRef );
exit(ret);
}