#include <sys/stat.h>
#include <sys/time.h>
#include <PasswordServer/AuthFile.h>
#include "CAuthAuthority.h"
#include "PwdPolicyTool.h"
#define debugerr(ERR, A, args...) if (gVerbose && (ERR)) {fprintf(stderr, (A), ##args);}
const long kBuffSize = 8192;
PwdPolicyTool::PwdPolicyTool ( void )
{
fDSRef = 0;
fTDataBuff = 0;
fLocalNodeRef = 0;
fSearchNodeRef = 0;
}
PwdPolicyTool::~PwdPolicyTool ( void )
{
}
tDirNodeReference PwdPolicyTool::GetLocalNodeRef ( void )
{
return( fLocalNodeRef );
}
tDirNodeReference PwdPolicyTool::GetSearchNodeRef ( void )
{
return( fSearchNodeRef );
}
tDirStatus PwdPolicyTool::Initialize ( void )
{
tDirStatus siStatus = eDSNoErr;
char **pNodeName = NULL;
siStatus = OpenDirectoryServices();
if ( siStatus != eDSNoErr )
{
return( siStatus );
}
siStatus = AllocateTDataBuff();
if ( siStatus != eDSNoErr )
{
return( siStatus );
}
siStatus = FindDirectoryNodes( nil, eDSSearchNodeName, &pNodeName );
if ( siStatus == eDSNoErr )
{
if ( pNodeName[0] != NULL ) {
siStatus = OpenDirNode( pNodeName[0], &fSearchNodeRef );
free( pNodeName[0] );
}
free( pNodeName );
pNodeName = NULL;
if ( siStatus != eDSNoErr )
{
return( siStatus );
}
}
else
{
return( siStatus );
}
return( siStatus );
}
tDirStatus PwdPolicyTool::Deinitialize ( void )
{
tDirStatus siStatus = eDSNoErr;
siStatus = DeallocateTDataBuff();
if ( siStatus != eDSNoErr )
{
PrintError( siStatus, "DeallocateTDataBuff" );
}
siStatus = CloseDirectoryNode( fLocalNodeRef );
if ( siStatus != eDSNoErr )
{
::fprintf( stderr, "error in CloseDirectoryNode %ld\n", (long) siStatus );
}
siStatus = CloseDirectoryNode( fSearchNodeRef );
if ( siStatus != eDSNoErr )
{
PrintError( siStatus, "CloseDirectoryNode" );
}
siStatus = CloseDirectoryServices();
if ( siStatus != eDSNoErr )
{
PrintError( siStatus, "CloseDirectoryServices" );
}
return( siStatus );
}
tDirStatus PwdPolicyTool::OpenDirectoryServices ( void )
{
tDirStatus error = eDSNoErr;
if ( gVerbose == true )
{
fprintf( stderr, "\n----- Opening Directory Services -----\n" );
}
error = dsOpenDirService( &fDSRef );
if ( error != eDSNoErr )
{
PrintError( error, "dsOpenDirService" );
}
else if ( gVerbose == true )
{
fprintf( stderr, " Directory Reference = %ld.\n", fDSRef );
}
return( error );
}
tDirStatus PwdPolicyTool::CloseDirectoryServices ( void )
{
tDirStatus error = eDSNoErr;
if ( gVerbose == true )
{
fprintf( stderr, "\n----- Closing Directory Services -----\n" );
}
error = dsCloseDirService( fDSRef );
if ( error != eDSNoErr )
{
PrintError( error, "dsCloseDirService" );
}
return( error );
}
tDirStatus PwdPolicyTool::AllocateTDataBuff ( void )
{
tDirStatus error = eDSNoErr;
if ( gVerbose == true )
{
fprintf( stderr, "\n----- Allocating a %ldK buffer -----\n", kBuffSize / 1024 );
}
fTDataBuff = dsDataBufferAllocate( fDSRef, kBuffSize );
if ( fTDataBuff == nil )
{
PrintError( eMemoryAllocError, "dsDataBufferAllocate" );
error = eMemoryAllocError;
}
if ( gVerbose == true )
{
fprintf( stderr, " allocated buffer of %ld size.\n", fTDataBuff->fBufferSize );
}
return( error );
}
tDirStatus PwdPolicyTool::DeallocateTDataBuff ( void )
{
tDirStatus error = eDSNoErr;
if ( gVerbose == true )
{
fprintf( stderr, "\n----- Deallocating default buffer -----\n" );
}
error = dsDataBufferDeAllocate( fDSRef, fTDataBuff );
if ( error != eDSNoErr )
{
PrintError( error, "dsDataBufferDeAllocate" );
}
return( error );
}
tDirStatus PwdPolicyTool::DoGetRecordList ( tDirNodeReference inNodeRef,
const char *inRecName,
const char *inRecType,
const char *inAttrType,
tDirPatternMatch inMatchType, char **outAuthAuthority,
char **outNodeName )
{
tDirStatus error = eDSNoErr;
tDirStatus error2 = eDSNoErr;
UInt32 recCount = 1;
tContextData context = nil;
tDataList *pRecName = nil;
tDataList *pRecType = nil;
tDataList *pAttrType = nil;
if ( gVerbose == true )
{
fprintf( stderr, "\n----- Getting Record List -----\n" );
fprintf( stderr, " Record Name = %s\n", inRecName );
fprintf( stderr, " Record Type = %s\n", inRecType );
fprintf( stderr, " Attribute Type = %s\n", inAttrType );
}
pRecName = dsBuildListFromStrings( fDSRef, inRecName, nil );
if ( pRecName != nil )
{
pRecType = dsBuildListFromStrings( fDSRef, inRecType, nil );
if ( pRecType != nil )
{
pAttrType = dsBuildListFromStrings( fDSRef, inAttrType, kDSNAttrMetaNodeLocation, nil );
if ( pAttrType != nil )
{
*outAuthAuthority = NULL;
*outNodeName = NULL;
do
{
error = dsGetRecordList( inNodeRef, fTDataBuff, pRecName, inMatchType, pRecType,
pAttrType, false, &recCount, &context );
if ( error == eDSNoErr )
{
error = GetDataFromDataBuff( inNodeRef, fTDataBuff, recCount, outAuthAuthority, outNodeName );
}
else if ( error == eDSBufferTooSmall )
{
UInt32 buffSize = fTDataBuff->fBufferSize;
dsDataBufferDeAllocate( fDSRef, fTDataBuff );
fTDataBuff = nil;
fTDataBuff = dsDataBufferAllocate( fDSRef, buffSize * 2 );
}
} while ( ((error == eDSNoErr) && (context != 0)) || (error == eDSBufferTooSmall) );
error2 = dsDataListDeallocate( fDSRef, pAttrType );
if ( error2 != eDSNoErr )
{
PrintError( error2, "dsDataListDeallocate" );
}
}
else
{
PrintError( eMemoryAllocError, "dsBuildListFromStrings" );
error = eMemoryAllocError;
}
error2 = dsDataListDeallocate( fDSRef, pRecType );
if ( error2 != eDSNoErr )
{
PrintError( error2, "dsDataListDeallocate" );
}
}
else
{
PrintError( eMemoryAllocError, "dsBuildListFromStrings" );
error = eMemoryAllocError;
}
error2 = dsDataListDeallocate( fDSRef, pRecName );
if ( error2 != eDSNoErr )
{
PrintError( error2, "dsDataListDeallocate" );
}
}
else
{
PrintError( eMemoryAllocError, "dsBuildListFromStrings" );
error = eMemoryAllocError;
}
return( error );
}
tDirStatus PwdPolicyTool::GetDataFromDataBuff(
tDirNodeReference inNodeRef,
tDataBuffer *inTDataBuff,
UInt32 inRecCount,
char **outAuthAuthority,
char **outNodeName )
{
tDirStatus error = eDSNoErr;
UInt32 i = 0;
UInt32 j = 0;
UInt32 k = 0;
char *pRecNameStr = nil;
char *pRecTypeStr = nil;
tRecordEntry *pRecEntry = nil;
tAttributeListRef attrListRef = 0;
tAttributeValueListRef valueRef = 0;
tAttributeEntry *pAttrEntry = nil;
tAttributeValueEntry *pValueEntry = nil;
bool found = false;
if ( gVerbose == true )
{
fprintf( stderr, " Record count = %ld\n", inRecCount );
}
if ( (inRecCount != 0) && (inNodeRef != 0) && (inTDataBuff != nil) )
{
for ( i = 1; (i <= inRecCount) && (error == eDSNoErr) && (!found); i++ )
{
error = dsGetRecordEntry( inNodeRef, inTDataBuff, i, &attrListRef, &pRecEntry );
if ( error == eDSNoErr && pRecEntry != NULL )
{
error = dsGetRecordNameFromEntry( pRecEntry, &pRecNameStr );
if ( error == eDSNoErr )
{
error = dsGetRecordTypeFromEntry( pRecEntry, &pRecTypeStr );
if ( error == eDSNoErr )
{
if ( gVerbose == true )
{
fprintf( stderr, "\n" );
fprintf( stderr, " Record Number = %ld\n", i );
fprintf( stderr, " Record Name = %s\n", pRecNameStr );
fprintf( stderr, " Record Type = %s\n", pRecTypeStr );
fprintf( stderr, " Attribute count = %ld\n", pRecEntry->fRecordAttributeCount );
}
for ( j = 1; (j <= pRecEntry->fRecordAttributeCount) && (error == eDSNoErr); j++ )
{
error = dsGetAttributeEntry( inNodeRef, inTDataBuff, attrListRef, j, &valueRef, &pAttrEntry );
if ( error == eDSNoErr && pAttrEntry != NULL )
{
for ( k = 1; (k <= pAttrEntry->fAttributeValueCount) && (error == eDSNoErr); k++ )
{
error = dsGetAttributeValue( inNodeRef, inTDataBuff, k, valueRef, &pValueEntry );
if ( error == eDSNoErr && pValueEntry != NULL )
{
if ( gVerbose == true )
{
fprintf( stderr, " %ld - %ld: (%s) %s\n", j, k,
pAttrEntry->fAttributeSignature.fBufferData,
pValueEntry->fAttributeValueData.fBufferData );
}
if ( !found &&
(strcasestr( pValueEntry->fAttributeValueData.fBufferData, kDSTagAuthAuthorityPasswordServer ) != NULL ||
strcasestr( pValueEntry->fAttributeValueData.fBufferData, kDSTagAuthAuthorityShadowHash ) != NULL) )
{
*outAuthAuthority = (char *) malloc( pValueEntry->fAttributeValueData.fBufferLength + 1 );
strcpy( *outAuthAuthority, pValueEntry->fAttributeValueData.fBufferData );
dsDeallocAttributeValueEntry( fDSRef, pValueEntry );
pValueEntry = NULL;
found = true;
}
else
if ( strcasestr( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrMetaNodeLocation ) != NULL )
{
*outNodeName = (char *) malloc( pValueEntry->fAttributeValueData.fBufferLength + 1 );
strcpy( *outNodeName, pValueEntry->fAttributeValueData.fBufferData );
dsDeallocAttributeValueEntry( fDSRef, pValueEntry );
pValueEntry = NULL;
}
dsDeallocAttributeValueEntry( fDSRef, pValueEntry );
pValueEntry = NULL;
}
else
{
PrintError( error, "dsGetAttributeValue" );
}
}
dsDeallocAttributeEntry( fDSRef, pAttrEntry );
pAttrEntry = NULL;
dsCloseAttributeValueList(valueRef);
valueRef = 0;
}
else
{
PrintError( error, "dsGetAttributeEntry" );
}
}
delete( pRecTypeStr );
pRecTypeStr = nil;
}
else
{
PrintError( error, "dsGetRecordTypeFromEntry" );
}
delete( pRecNameStr );
pRecNameStr = nil;
}
else
{
PrintError( error, "dsGetRecordNameFromEntry" );
}
dsDeallocRecordEntry( fDSRef, pRecEntry );
pRecEntry = NULL;
dsCloseAttributeList( attrListRef );
attrListRef = 0;
}
else
{
PrintError( error, "dsGetRecordEntry" );
}
}
}
return( error );
}
tDirStatus PwdPolicyTool::FindDirectoryNodes( char *inNodeName,
tDirPatternMatch inMatch,
char **outNodeNameList[],
bool inPrintNames )
{
tDirStatus error = eDSNoErr;
tDirStatus error2 = eDSNoErr;
UInt32 uiCount = 0;
UInt32 uiIndex = 0;
UInt32 outIndex = 0;
tDataList *pNodeNameList = nil;
tDataList *pDataList = nil;
char *pNodeName = nil;
if ( gVerbose == true )
{
fprintf( stderr, "\n----- Finding node(s) -----\n" );
fprintf( stderr, " Node Name: %s\n", inNodeName );
fprintf( stderr, " Pattern Match: %d\n", inMatch );
}
try
{
if ( fTDataBuff == NULL )
throw( (tDirStatus)eDSNullParameter );
if ( inNodeName != nil )
{
pNodeNameList = dsBuildFromPath( fDSRef, inNodeName, "/" );
if ( pNodeNameList == nil )
{
PrintError( eMemoryAllocError, "dsBuildFromPath" );
throw( (tDirStatus)eMemoryAllocError );
}
}
do {
error = dsFindDirNodes( fDSRef, fTDataBuff, pNodeNameList, inMatch, &uiCount, nil );
if ( error == eDSBufferTooSmall )
{
UInt32 buffSize = fTDataBuff->fBufferSize;
dsDataBufferDeAllocate( fDSRef, fTDataBuff );
fTDataBuff = nil;
fTDataBuff = dsDataBufferAllocate( fDSRef, buffSize * 2 );
}
} while ( error == eDSBufferTooSmall );
if ( error == eDSNoErr )
{
if ( inPrintNames || gVerbose )
{
fprintf( stderr, " Node count = %ld.\n", uiCount );
}
if ( uiCount != 0 )
{
*outNodeNameList = (char **) calloc(uiCount + 1, sizeof(char *));
if ( *outNodeNameList == NULL )
throw((tDirStatus)eMemoryError);
pDataList = dsDataListAllocate( fDSRef );
if ( pDataList != nil )
{
for ( uiIndex = 1; (uiIndex <= uiCount) && (error == eDSNoErr); uiIndex++ )
{
error = dsGetDirNodeName( fDSRef, fTDataBuff, uiIndex, &pDataList );
if ( error == eDSNoErr )
{
pNodeName = dsGetPathFromList( fDSRef, pDataList, "/" );
if ( pNodeName != nil )
{
if ( inPrintNames || gVerbose )
{
fprintf( stderr, " %2ld - Node Name = %s\n", uiIndex, pNodeName );
}
(*outNodeNameList)[outIndex++] = pNodeName;
error2 = dsDataListDeallocate( fDSRef, pDataList );
if ( error2 != eDSNoErr )
{
PrintError( error2, "dsDataListDeallocate" );
}
}
else
{
PrintError( eMemoryAllocError, "dsGetPathFromList" );
error = eMemoryAllocError;
}
}
else
{
PrintError( error, "dsGetDirNodeName" );
}
}
}
else
{
PrintError( eMemoryAllocError, "dsDataListAllocate" );
error = eMemoryAllocError;
}
}
}
else
{
PrintError( error, "dsFindDirNodes" );
}
if ( pNodeNameList != nil )
{
error2 = dsDataListDeallocate( fDSRef, pNodeNameList );
if ( error2 != eDSNoErr )
{
PrintError( error2, "dsDataListDeallocate" );
}
}
}
catch ( tDirStatus err )
{
PrintError( err, "FindDirectoryNodes" );
error = err;
}
return( error );
}
tDirStatus PwdPolicyTool::OpenLocalNode( tDirNodeReference *outNodeRef )
{
char **localNodeNameList = NULL;
tDirStatus result = this->FindDirectoryNodes( NULL, eDSLocalNodeNames, &localNodeNameList, false );
if ( result == eDSNoErr )
{
if ( localNodeNameList != NULL && localNodeNameList[0] != NULL )
{
result = this->OpenDirNode( localNodeNameList[0], outNodeRef );
free( localNodeNameList[0] );
free( localNodeNameList );
}
else
{
result = eDSOpenNodeFailed;
}
}
return result;
}
tDirStatus PwdPolicyTool::OpenDirNode ( char *inNodeName, tDirNodeReference *outNodeRef )
{
tDirStatus error = eDSNoErr;
tDirStatus error2 = eDSNoErr;
tDataList *pDataList = nil;
if ( gVerbose == true )
{
fprintf( stderr, "\n----- Opening Directory Node -----\n" );
fprintf( stderr, " Node Name: %s\n", inNodeName );
}
pDataList = dsBuildFromPath( fDSRef, inNodeName, "/" );
if ( pDataList != nil )
{
error = dsOpenDirNode( fDSRef, pDataList, outNodeRef );
if (error == eDSNoErr)
{
if (gVerbose == true)
{
fprintf( stderr, " Open Node Reference = %ld.\n", *outNodeRef );
}
}
else
{
PrintError( error, "dsOpenDirNode" );
}
error2 = dsDataListDeallocate( fDSRef, pDataList );
if ( error2 != eDSNoErr )
{
PrintError( error2, "dsDataListDeallocate" );
}
}
else
{
PrintError( eMemoryAllocError, "dsBuildFromPath" );
error = eMemoryAllocError;
}
return( error );
}
tDirStatus PwdPolicyTool::CloseDirectoryNode ( tDirNodeReference inNodeRef )
{
tDirStatus error = eDSNoErr;
if ( gVerbose == true )
{
fprintf( stderr, "\n----- Closing Directory Node -----\n" );
fprintf( stderr, " Node Reference: %lu\n", inNodeRef );
}
if ( inNodeRef == 0 )
return eDSNoErr;
error = dsCloseDirNode( inNodeRef );
if ( error != eDSNoErr )
{
PrintError( error, "dsCloseDirNode" );
}
return( error );
}
tDirStatus
PwdPolicyTool::DoNodePWAuth(
tDirNodeReference inNode,
const char *inName,
const char *inPasswd,
const char *inMethod,
const char *inUserName,
const char *inOther,
const char *inRecordType,
char *outResult )
{
tDirStatus error = eDSNoErr;
tDirStatus error2 = eDSNoErr;
tDataBuffer *pAuthBuff = nil;
tDataBuffer *pStepBuff = nil;
tDataNode *pAuthType = nil;
tDataNodePtr recordTypeNode = NULL;
tContextData context = 0;
if ( gVerbose == true )
{
fprintf( stderr, "\n----- Node Password Server Auth -----\n" );
fprintf( stderr, " User Name = %s\n", inName );
}
recordTypeNode = dsDataNodeAllocateString( fDSRef, inRecordType ? inRecordType : kDSStdRecordTypeUsers );
error = SetUpAuthBuffs( &pAuthBuff, 2048, &pStepBuff, 2048, &pAuthType, inMethod );
if ( error == eDSNoErr )
{
if ( inName == NULL )
inName = "";
if ( inPasswd == NULL )
inPasswd = "";
if ( strcmp(kDSStdAuthGetEffectivePolicy, inMethod) == 0 )
{
error = dsFillAuthBuffer( pAuthBuff, 1,
::strlen( inUserName ), inUserName);
}
else
if ( inOther != NULL )
{
error = dsFillAuthBuffer( pAuthBuff, 4,
::strlen( inName ), inName,
::strlen( inPasswd ), inPasswd,
::strlen( inUserName ), inUserName,
::strlen( inOther ), inOther );
}
else
if ( inUserName != NULL )
{
error = dsFillAuthBuffer( pAuthBuff, 3,
::strlen( inName ), inName,
::strlen( inPasswd ), inPasswd,
::strlen( inUserName ), inUserName );
}
else
{
error = dsFillAuthBuffer( pAuthBuff, 2,
::strlen( inName ), inName,
::strlen( inPasswd ), inPasswd );
}
if ( error == eDSNoErr )
{
if ( inRecordType == NULL || strcmp(inRecordType, kDSStdRecordTypeUsers) == 0 )
error = dsDoDirNodeAuth( inNode, pAuthType, true, pAuthBuff, pStepBuff, &context );
else
error = dsDoDirNodeAuthOnRecordType( inNode, pAuthType, true, pAuthBuff, pStepBuff, nil, recordTypeNode );
if ( error == eDSNoErr )
{
UInt32 len;
memcpy(&len, pStepBuff->fBufferData, 4);
if ( len < pStepBuff->fBufferSize - 4 )
{
pStepBuff->fBufferData[len+4] = '\0';
if ( outResult != NULL )
strcpy( outResult, pStepBuff->fBufferData+4 );
else
fprintf( stdout, "%s\n", pStepBuff->fBufferData+4 );
}
else
{
if ( outResult != NULL )
sprintf( outResult, "The buffer data length is invalid (len=%lu).", len );
else
fprintf( stdout, "The buffer data length is invalid (len=%lu).\n", len );
}
}
else
{
PrintError( error, "dsDoDirNodeAuth" );
fprintf( stderr, " Method = %s\n", inMethod );
}
}
error2 = dsDataBufferDeAllocate( fDSRef, pAuthBuff );
if ( error2 != eDSNoErr )
{
PrintError( error2, "dsDataBufferDeAllocate" );
}
error2 = dsDataBufferDeAllocate( fDSRef, pStepBuff );
if ( error2 != eDSNoErr )
{
PrintError( error2, "dsDataBufferDeAllocate" );
}
error2 = dsDataBufferDeAllocate( fDSRef, pAuthType );
if ( error2 != eDSNoErr )
{
PrintError( error2, "dsDataBufferDeAllocate" );
}
}
if ( recordTypeNode )
dsDataNodeDeAllocate( fDSRef, recordTypeNode );
return( error );
}
tDirStatus PwdPolicyTool::DoNodeNativeAuth ( tDirNodeReference inNode, const char *inName, const char *inPasswd )
{
tDirStatus error = eDSNoErr;
tDirStatus error2 = eDSNoErr;
tDataBuffer *pAuthBuff = nil;
tDataBuffer *pStepBuff = nil;
tDataNode *pAuthType = nil;
if ( gVerbose == true )
{
fprintf( stderr, "\n----- Node Auth -----\n" );
fprintf( stderr, " User Name = %s\n", inName );
}
error = SetUpAuthBuffs( &pAuthBuff, 2048, &pStepBuff, 2048, &pAuthType, kDSStdAuthNodeNativeClearTextOK );
if ( error == eDSNoErr )
{
if ( inName == NULL )
inName = "";
if ( inPasswd == NULL )
inPasswd = "";
error = dsFillAuthBuffer( pAuthBuff, 2, strlen( inName ), inName, strlen( inPasswd ), inPasswd );
if ( error == eDSNoErr )
{
error = dsDoDirNodeAuth( inNode, pAuthType, false, pAuthBuff, pStepBuff, nil );
if ( error != eDSNoErr )
{
PrintError( error, "dsDoDirNodeAuth" );
}
}
error2 = dsDataBufferDeAllocate( fDSRef, pAuthBuff );
if ( error2 != eDSNoErr )
{
PrintError( error2, "dsDataBufferDeAllocate" );
}
error2 = dsDataBufferDeAllocate( fDSRef, pStepBuff );
if ( error2 != eDSNoErr )
{
PrintError( error2, "dsDataBufferDeAllocate" );
}
error2 = dsDataBufferDeAllocate( fDSRef, pAuthType );
if ( error2 != eDSNoErr )
{
PrintError( error2, "dsDataBufferDeAllocate" );
}
}
return( error );
}
void PwdPolicyTool::PrintError ( long inErrCode, const char *messageTag )
{
char *statusString = nil;
if (inErrCode == eDSNoErr)
{
return;
}
statusString = dsCopyDirStatusName(inErrCode);
if ( messageTag == nil )
{
fprintf( stderr, "\n***Error: %s : (%ld)\n", statusString, inErrCode );
}
else
{
fprintf( stderr, "\n***Error: %s : (%ld) for %s\n", statusString, inErrCode, messageTag );
}
free(statusString);
statusString = nil;
fflush( stderr );
}
tDirStatus PwdPolicyTool::SetUpAuthBuffs ( tDataBuffer **outAuthBuff,
UInt32 inAuthBuffSize,
tDataBuffer **outStepBuff,
UInt32 inStepBuffSize,
tDataBuffer **outTypeBuff,
const char *inAuthMethod )
{
tDirStatus error = eDSNoErr;
tDirStatus error2 = eDSNoErr;
if ( (outAuthBuff == nil) || (outStepBuff == nil) ||
(outTypeBuff == nil) || (inAuthMethod == nil) )
{
return( eDSNullParameter );
}
*outAuthBuff = dsDataBufferAllocate( fDSRef, inAuthBuffSize );
if ( *outAuthBuff != nil )
{
*outStepBuff = dsDataBufferAllocate( fDSRef, inStepBuffSize );
if ( *outStepBuff != nil )
{
*outTypeBuff = dsDataNodeAllocateString( fDSRef, inAuthMethod );
if ( *outTypeBuff == nil )
{
PrintError( eMemoryAllocError, "dsDataNodeAllocateString" );
error = eMemoryAllocError;
}
}
else
{
PrintError( eMemoryAllocError, "dsDataBufferAllocate" );
error = eMemoryAllocError;
}
}
else
{
PrintError( eMemoryAllocError, "dsDataBufferAllocate" );
error = eMemoryAllocError;
}
if ( error != eDSNoErr )
{
if ( *outAuthBuff != nil )
{
error2 = dsDataBufferDeAllocate( fDSRef, *outAuthBuff );
if ( error2 != eDSNoErr )
{
PrintError( error2, "dsDataBufferDeAllocate" );
}
}
if ( *outStepBuff != nil )
{
error2 = dsDataBufferDeAllocate( fDSRef, *outStepBuff );
if ( error2 != eDSNoErr )
{
PrintError( error2, "dsDataBufferDeAllocate" );
}
}
if ( *outTypeBuff != nil )
{
error2 = dsDataBufferDeAllocate( fDSRef, *outTypeBuff );
if ( error2 != eDSNoErr )
{
PrintError( error2, "dsDataBufferDeAllocate" );
}
}
}
return( error );
}
tDirStatus
PwdPolicyTool::GetUserByName(
tDirNodeReference inNode,
const char *inUserName,
const char *inRecordType,
char **outAuthAuthority,
char **outNodeName )
{
tDirStatus status = eDSNoErr;
if (gVerbose)
fprintf( stderr, "\n----- Getting user by name: %s -----\n", inUserName );
status = DoGetRecordList( inNode, inUserName, inRecordType, kDSNAttrAuthenticationAuthority, eDSExact, outAuthAuthority, outNodeName );
if ( outAuthAuthority && *outAuthAuthority == NULL )
{
char *unamePlusDollar = (char *) malloc( strlen(inUserName) + 2 );
strcpy( unamePlusDollar, inUserName );
strcat( unamePlusDollar, "$" );
status = DoGetRecordList( inNode, unamePlusDollar, inRecordType, kDSNAttrAuthenticationAuthority, eDSExact, outAuthAuthority, outNodeName );
}
if ( status != eDSNoErr )
{
fprintf( stderr, " *** GetRecordList failed with error = %ld.\n", (long) status );
}
return( status );
}
tDirStatus
PwdPolicyTool::OpenRecord(
tDirNodeReference inNodeRef,
const char *inRecordType,
const char *inRecordName,
tRecordReference *outRecordRef,
bool inCreate )
{
tDirStatus status = eDSNoErr;
tDataNodePtr recordTypeNode = NULL;
tDataNodePtr recordNameNode = NULL;
if ( fDSRef == 0 || inNodeRef == 0 || inRecordType == NULL || inRecordName == NULL || outRecordRef == NULL )
return eParameterError;
recordTypeNode = dsDataNodeAllocateString( fDSRef, inRecordType );
recordNameNode = dsDataNodeAllocateString( fDSRef, inRecordName );
status = dsOpenRecord( inNodeRef, recordTypeNode, recordNameNode, outRecordRef );
if ( inCreate && status == eDSRecordNotFound )
status = dsCreateRecordAndOpen( inNodeRef, recordTypeNode, recordNameNode, outRecordRef );
if ( recordTypeNode ) {
dsDataNodeDeAllocate( fDSRef, recordTypeNode );
recordTypeNode = NULL;
}
if ( recordNameNode ) {
dsDataNodeDeAllocate( fDSRef, recordNameNode );
recordNameNode = NULL;
}
return status;
}
void
PwdPolicyTool::ChangeAuthAuthorityToShadowHash( tRecordReference inRecordRef )
{
long status = eDSNoErr;
tAttributeValueEntry *pExistingAttrValue = NULL;
UInt32 attrValIndex = 0;
UInt32 attrValCount = 0;
tDataNode *attrTypeNode = nil;
tAttributeEntryPtr pAttrEntry = nil;
char *aaString = NULL;
char *aaEnableString = NULL;
UInt32 attrValueIDToReplace = 0;
CAuthAuthority aaTank;
try
{
pExistingAttrValue = nil;
attrValueIDToReplace = 0;
attrTypeNode = dsDataNodeAllocateString( 0, kDSNAttrAuthenticationAuthority );
status = dsGetRecordAttributeInfo( inRecordRef, attrTypeNode, &pAttrEntry );
debugerr(status, "dsGetRecordAttributeInfo = %ld\n", status);
if ( status == eDSNoErr )
{
attrValCount = pAttrEntry->fAttributeValueCount;
for ( attrValIndex = 1; attrValIndex <= attrValCount; attrValIndex++ )
{
status = dsGetRecordAttributeValueByIndex( inRecordRef, attrTypeNode, attrValIndex, &pExistingAttrValue );
debugerr(status, "dsGetRecordAttributeValueByIndex = %ld\n", status);
if ( status == eDSNoErr )
aaTank.AddValue( pExistingAttrValue->fAttributeValueData.fBufferData );
}
}
int aaIndex = 0;
int aaCount = aaTank.GetValueCount();
tDataListPtr dataList = dsDataListAllocate( 0 );
for ( aaIndex = 0; aaIndex < aaCount; aaIndex++ )
{
aaString = aaTank.GetValueAtIndex( aaIndex );
if ( strncasecmp(aaString, kDSValueAuthAuthorityDisabledUser, sizeof(kDSValueAuthAuthorityDisabledUser) - 1) == 0 )
aaEnableString = aaString + sizeof(kDSValueAuthAuthorityDisabledUser) - 1;
else
aaEnableString = aaString;
status = dsAppendStringToListAlloc( 0, dataList, aaEnableString );
}
status = dsSetAttributeValues( inRecordRef, attrTypeNode, dataList );
debugerr(status, "dsSetAttributeValues = %ld\n", status);
}
catch(...)
{
}
}
int
PwdPolicyTool::SetUserHashList( tRecordReference inRecordRef, int firstArg, int argc, char * const *argv )
{
long status = eDSNoErr;
int returnValue = 0;
tAttributeValueEntry *pExistingAttrValue = NULL;
UInt32 attrValIndex = 0;
UInt32 attrValCount = 0;
tDataNode *attrTypeNode = NULL;
tAttributeEntryPtr pAttrEntry = NULL;
char *aaVersion = NULL;
char *aaTag = NULL;
char *aaData = NULL;
char *aaNewData = NULL;
UInt32 attrValueIDToReplace = 0;
CFMutableArrayRef hashTypeArray = NULL;
CFStringRef stringRef = NULL;
char *newDataStr = NULL;
long len = 0;
try
{
pExistingAttrValue = nil;
attrValueIDToReplace = 0;
attrTypeNode = dsDataNodeAllocateString( 0, kDSNAttrAuthenticationAuthority );
status = dsGetRecordAttributeInfo( inRecordRef, attrTypeNode, &pAttrEntry );
debugerr(status, "dsGetRecordAttributeInfo = %ld\n", status);
if ( status == eDSNoErr )
{
attrValCount = pAttrEntry->fAttributeValueCount;
for ( attrValIndex = 1; attrValIndex <= attrValCount; attrValIndex++ )
{
status = dsGetRecordAttributeValueByIndex( inRecordRef, attrTypeNode, attrValIndex, &pExistingAttrValue );
debugerr(status, "dsGetRecordAttributeValueByIndex = %ld\n", status);
if (status != eDSNoErr) continue;
status = dsParseAuthAuthority( pExistingAttrValue->fAttributeValueData.fBufferData, &aaVersion, &aaTag, &aaData );
if ( status == eDSNoErr )
{
if ( strcasecmp( aaTag, kDSTagAuthAuthorityShadowHash ) == 0 )
{
attrValueIDToReplace = pExistingAttrValue->fAttributeValueID;
if ( pwsf_ShadowHashDataToArray( aaData, &hashTypeArray ) == 0 )
{
if ( this->GetHashTypeArray( &hashTypeArray ) != 0 )
{
hashTypeArray = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
if ( hashTypeArray == NULL ) {
fprintf(stderr, "memory error\n");
return 0;
}
AppendHashTypeToArray( "SALTED-SHA1", hashTypeArray );
}
}
break;
}
if ( aaVersion != NULL ) { free( aaVersion ); aaVersion = NULL; }
if ( aaTag != NULL ) { free( aaTag ); aaTag = NULL; }
if ( aaData != NULL ) { free( aaData ); aaData = NULL; }
}
}
}
if ( status == eDSNoErr && attrValueIDToReplace != 0 )
{
tAttributeValueEntry *pNewPWAttrValue = NULL;
CFIndex typeCount;
CFIndex hashTypeIndex;
CFRange arrayRange;
if ( firstArg >= argc - 1 )
{
returnValue = -1;
throw( returnValue );
}
for ( int argIndex = firstArg; argIndex < argc - 1; argIndex += 2 )
{
stringRef = CFStringCreateWithCString( kCFAllocatorDefault, argv[argIndex], kCFStringEncodingUTF8 );
if ( stringRef == NULL )
continue;
typeCount = CFArrayGetCount( hashTypeArray );
arrayRange = CFRangeMake( 0, typeCount );
if ( strcasecmp( argv[argIndex + 1], "on" ) == 0 )
{
if ( ! CFArrayContainsValue( hashTypeArray, arrayRange, (const void *)stringRef ) )
CFArrayAppendValue( hashTypeArray, (const void *)stringRef );
}
else
if ( strcasecmp( argv[argIndex + 1], "off" ) == 0 )
{
do
{
hashTypeIndex = CFArrayGetFirstIndexOfValue( hashTypeArray, arrayRange, (const void *)stringRef );
if ( hashTypeIndex != kCFNotFound )
{
CFArrayRemoveValueAtIndex( hashTypeArray, hashTypeIndex );
typeCount--;
arrayRange.length--;
}
}
while ( hashTypeIndex != kCFNotFound );
}
else
{
returnValue = -1;
throw( returnValue );
}
CFRelease( stringRef );
}
newDataStr = pwsf_ShadowHashArrayToData( hashTypeArray, &len );
aaNewData = (char *) malloc( sizeof(kDSValueAuthAuthorityShadowHash) + len + 1 );
if ( aaNewData != NULL )
{
len = sprintf( aaNewData, "%s%s", kDSValueAuthAuthorityShadowHash, newDataStr );
pNewPWAttrValue = dsAllocAttributeValueEntry( fDSRef, attrValueIDToReplace, aaNewData, len );
if ( pNewPWAttrValue != nil )
{
status = dsSetAttributeValue( inRecordRef, attrTypeNode, pNewPWAttrValue );
dsDeallocAttributeValueEntry( fDSRef, pNewPWAttrValue );
pNewPWAttrValue = NULL;
}
}
debugerr( status, "status(1) = %ld.\n", status );
}
else
{
debugerr(status, "ds error = %ld\n", status);
}
}
catch(...)
{
}
CFRelease( hashTypeArray );
return returnValue;
}
long
PwdPolicyTool::GetHashTypes( char **outHashTypesStr, bool inExcludeLMHash )
{
CFMutableArrayRef hashTypeArray;
CFIndex index, typeCount;
CFStringRef stringRef;
char mech[256];
char scratchStr[256] = {0};
long status = GetHashTypeArray( &hashTypeArray );
if ( status != eDSNoErr )
return status;
typeCount = CFArrayGetCount( hashTypeArray );
for ( index = 0; index < typeCount; index++ )
{
stringRef = (CFStringRef)CFArrayGetValueAtIndex( hashTypeArray, index );
if ( stringRef == NULL )
continue;
if ( CFStringGetCString( stringRef, mech, sizeof(mech), kCFStringEncodingUTF8 ) )
{
if ( !inExcludeLMHash || strcasecmp(mech, "SMB-LAN-MANAGER") != 0 )
{
if ( scratchStr[0] != '\0' )
strlcat( scratchStr, "\n", sizeof(scratchStr) );
strlcat( scratchStr, mech, sizeof(scratchStr) );
}
}
}
*outHashTypesStr = (char *) malloc( strlen(scratchStr) + 1 );
if ( (*outHashTypesStr) != NULL )
strcpy( *outHashTypesStr, scratchStr );
CFRelease( hashTypeArray );
return status;
}
long
PwdPolicyTool::SetHashTypes( const char *inName, char *inPasswd, int arg1, int argc, char * const *argv )
{
int argIndex;
CFIndex hashTypeIndex;
CFMutableArrayRef hashTypeArray = NULL;
tRecordReference recordRef = 0;
tDirNodeReference localNodeRef = 0;
tDataNode *attrTypeNode = NULL;
tDataNode *attrValueNode = NULL;
bool bNeedToAddAttribute;
bool serverOS = false;
struct stat statResult;
CFIndex typeCount;
CFRange arrayRange;
CFStringRef stringRef;
char mech[256];
long status = GetHashTypeArray( &hashTypeArray );
if ( status != eDSNoErr )
return status;
serverOS = (stat( "/System/Library/CoreServices/ServerVersion.plist", &statResult ) == 0);
for ( argIndex = arg1; argIndex < argc - 1; argIndex += 2 )
{
stringRef = CFStringCreateWithCString( kCFAllocatorDefault, argv[argIndex], kCFStringEncodingUTF8 );
if ( stringRef == NULL )
continue;
typeCount = CFArrayGetCount( hashTypeArray );
arrayRange = CFRangeMake( 0, typeCount );
if ( strcasecmp( argv[argIndex + 1], "on" ) == 0 )
{
if ( serverOS || strcmp(argv[argIndex], "RECOVERABLE") != 0 ) {
if ( ! CFArrayContainsValue( hashTypeArray, arrayRange, (const void *)stringRef ) )
CFArrayAppendValue( hashTypeArray, (const void *)stringRef );
}
}
else
if ( strcasecmp( argv[argIndex + 1], "off" ) == 0 )
{
do
{
hashTypeIndex = CFArrayGetFirstIndexOfValue( hashTypeArray, arrayRange, (const void *)stringRef );
if ( hashTypeIndex != kCFNotFound )
{
CFArrayRemoveValueAtIndex( hashTypeArray, hashTypeIndex );
typeCount--;
arrayRange.length--;
}
}
while ( hashTypeIndex != kCFNotFound );
}
CFRelease( stringRef );
}
try
{
status = this->OpenLocalNode( &localNodeRef );
if ( status != eDSNoErr ) throw ( status );
if ( inName != NULL && inPasswd != NULL )
{
status = this->DoNodeNativeAuth( localNodeRef, inName, inPasswd );
if ( status != eDSNoErr ) throw ( status );
}
status = this->OpenRecord( localNodeRef, kDSStdRecordTypeConfig, "shadowhash", &recordRef, true );
if ( status != eDSNoErr ) throw ( status );
attrTypeNode = dsDataNodeAllocateString( 0, kDSNativeAttrTypePrefix"optional_hash_list" );
dsRemoveAttribute( recordRef, attrTypeNode );
bNeedToAddAttribute = true;
typeCount = CFArrayGetCount( hashTypeArray );
for ( hashTypeIndex = 0; hashTypeIndex < typeCount; hashTypeIndex++ )
{
stringRef = (CFStringRef)CFArrayGetValueAtIndex( hashTypeArray, hashTypeIndex );
if ( stringRef == NULL )
continue;
if ( CFStringGetCString( stringRef, mech, sizeof(mech), kCFStringEncodingUTF8 ) )
{
attrValueNode = dsDataNodeAllocateString( 0, mech );
if ( attrValueNode != NULL )
{
if ( bNeedToAddAttribute )
{
status = dsAddAttribute( recordRef, attrTypeNode, NULL, attrValueNode );
bNeedToAddAttribute = false;
}
else
{
status = dsAddAttributeValue( recordRef, attrTypeNode, attrValueNode );
}
dsDataNodeDeAllocate( 0, attrValueNode );
attrValueNode = NULL;
}
}
}
}
catch( long catchStatus )
{
status = catchStatus;
}
if ( attrValueNode != NULL )
dsDataNodeDeAllocate( 0, attrValueNode );
if ( attrTypeNode != NULL )
dsDataNodeDeAllocate( 0, attrTypeNode );
if (recordRef != 0)
dsCloseRecord( recordRef );
this->CloseDirectoryNode( localNodeRef );
if ( hashTypeArray != NULL )
CFRelease( hashTypeArray );
return status;
}
long
PwdPolicyTool::GetHashTypeArray( CFMutableArrayRef *outHashTypeArray )
{
long status;
tRecordReference recordRef = 0;
tAttributeEntryPtr attributeInfo;
tAttributeValueEntry *pAttrValueEntry = NULL;
tDataNode *attrTypeNode = NULL;
bool attributeExists = false;
bool serverOS = false;
struct stat statResult;
tDirNodeReference localNodeRef = 0;
if ( outHashTypeArray == NULL )
return -1;
*outHashTypeArray = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
serverOS = (stat( "/System/Library/CoreServices/ServerVersion.plist", &statResult ) == 0);
try
{
status = this->OpenLocalNode( &localNodeRef );
if ( status != eDSNoErr )
throw( status );
status = this->OpenRecord( localNodeRef, kDSStdRecordTypeConfig, "shadowhash", &recordRef );
if ( status != eDSNoErr )
throw( status );
attrTypeNode = dsDataNodeAllocateString( 0, kDSNativeAttrTypePrefix"optional_hash_list" );
status = dsGetRecordAttributeInfo( recordRef, attrTypeNode, &attributeInfo );
if ( status != eDSNoErr )
throw( status );
attributeExists = true;
for ( unsigned int valueIndex = 1; valueIndex <= attributeInfo->fAttributeValueCount; valueIndex++ )
{
status = dsGetRecordAttributeValueByIndex( recordRef, attrTypeNode, valueIndex, &pAttrValueEntry );
if ( status != eDSNoErr )
continue;
if ( serverOS || strcmp(pAttrValueEntry->fAttributeValueData.fBufferData, "RECOVERABLE") != 0 )
AppendHashTypeToArray( pAttrValueEntry->fAttributeValueData.fBufferData, *outHashTypeArray );
dsDeallocAttributeValueEntry( fDSRef, pAttrValueEntry );
}
}
catch( long catchStatus )
{
status = catchStatus;
}
if ( ! attributeExists )
{
status = eDSNoErr;
if ( serverOS )
{
AppendHashTypeToArray( "CRAM-MD5", *outHashTypeArray );
AppendHashTypeToArray( "RECOVERABLE", *outHashTypeArray );
AppendHashTypeToArray( "SMB-LAN-MANAGER", *outHashTypeArray );
AppendHashTypeToArray( "SMB-NT", *outHashTypeArray );
}
AppendHashTypeToArray( "SALTED-SHA1", *outHashTypeArray );
}
if ( attrTypeNode != NULL )
dsDataNodeDeAllocate( 0, attrTypeNode );
if (recordRef != 0)
dsCloseRecord( recordRef );
this->CloseDirectoryNode( localNodeRef );
return status;
}
void
PwdPolicyTool::AppendHashTypeToArray( const char *inHashType, CFMutableArrayRef inHashTypeArray )
{
CFStringRef stringRef = CFStringCreateWithCString( kCFAllocatorDefault, inHashType, kCFStringEncodingUTF8 );
CFArrayAppendValue( inHashTypeArray, stringRef );
CFRelease( stringRef );
}