apple_authenticate.c [plain text]
#include "apple_authenticate.h"
#include <sys/types.h>
#include <pwd.h>
#include <Security/checkpw.h>
#include <syslog.h>
#include <CoreServices/CoreServices.h>
#include <CoreFoundation/CFData.h>
#include <CoreFoundation/CFString.h>
#include <CoreFoundation/CFNumber.h>
#include <CoreFoundation/CFPropertyList.h>
#include <DirectoryService/DirServices.h>
#include <DirectoryService/DirServicesUtils.h>
#include <DirectoryService/DirServicesConst.h>
enum { kLogErrors_disabled = 0, kLogErrors_enabled = 1 };
enum { kValidate_AuthMethod = 0, kValidate_User = 1 };
int authenticate_cram_md5 ( const char *inUserID, const char *inChallenge, const char *inResponse );
int apple_checkpw( const char* userName, const char* password );
int apple_checkpw( const char* userName, const char* password )
{
if (CHECKPW_SUCCESS == checkpw(userName, password))
return kAuthenticated;
return kFailed;
}
tDirStatus sOpen_user_node ( tDirReference inDirRef, const char *inUserLoc, tDirNodeReference *outUserNodeRef )
{
tDirStatus dsStatus = eMemoryAllocError;
tDataList *pUserNode = NULL;
pUserNode = dsBuildFromPath( inDirRef, inUserLoc, "/" );
if ( pUserNode != NULL )
{
dsStatus = dsOpenDirNode( inDirRef, pUserNode, outUserNodeRef );
(void)dsDataListDeAllocate( inDirRef, pUserNode, TRUE );
free( pUserNode );
pUserNode = NULL;
}
return( dsStatus );
}
tDirStatus sGet_search_node ( tDirReference inDirRef,
tDirNodeReference *outSearchNodeRef )
{
tDirStatus dsStatus = eMemoryAllocError;
unsigned long uiCount = 0;
tDataBuffer *pTDataBuff = NULL;
tDataList *pDataList = NULL;
pTDataBuff = dsDataBufferAllocate( inDirRef, 8192 );
if ( pTDataBuff != NULL )
{
dsStatus = dsFindDirNodes( inDirRef, pTDataBuff, NULL, eDSSearchNodeName, &uiCount, NULL );
if ( dsStatus == eDSNoErr )
{
dsStatus = eDSNodeNotFound;
if ( uiCount == 1 )
{
dsStatus = dsGetDirNodeName( inDirRef, pTDataBuff, 1, &pDataList );
if ( dsStatus == eDSNoErr )
{
dsStatus = dsOpenDirNode( inDirRef, pDataList, outSearchNodeRef );
}
if ( pDataList != NULL )
{
(void)dsDataListDeAllocate( inDirRef, pDataList, true );
free( pDataList );
pDataList = NULL;
}
}
}
(void)dsDataBufferDeAllocate( inDirRef, pTDataBuff );
pTDataBuff = NULL;
}
return( dsStatus );
}
tDirStatus sLook_up_user ( tDirReference inDirRef,
tDirNodeReference inSearchNodeRef,
const char *inUserID,
char **outUserLocation )
{
tDirStatus dsStatus = eMemoryAllocError;
int done = FALSE;
char *pAcctName = NULL;
unsigned long uiRecCount = 0;
tDataBuffer *pTDataBuff = NULL;
tDataList *pUserRecType = NULL;
tDataList *pUserAttrType = NULL;
tRecordEntry *pRecEntry = NULL;
tAttributeEntry *pAttrEntry = NULL;
tAttributeValueEntry *pValueEntry = NULL;
tAttributeValueListRef valueRef = 0;
tAttributeListRef attrListRef = 0;
tContextData pContext = NULL;
tDataList tdlRecName;
memset( &tdlRecName, 0, sizeof( tDataList ) );
pTDataBuff = dsDataBufferAllocate( inDirRef, 8192 );
if ( pTDataBuff != NULL )
{
dsStatus = dsBuildListFromStringsAlloc( inDirRef, &tdlRecName, inUserID, NULL );
if ( dsStatus == eDSNoErr )
{
dsStatus = eMemoryAllocError;
pUserRecType = dsBuildListFromStrings( inDirRef, kDSStdRecordTypeUsers, NULL );
if ( pUserRecType != NULL )
{
pUserAttrType = dsBuildListFromStrings( inDirRef, kDSNAttrMetaNodeLocation, NULL );
if ( pUserAttrType != NULL );
{
do {
dsStatus = dsGetRecordList( inSearchNodeRef, pTDataBuff, &tdlRecName, eDSiExact, pUserRecType,
pUserAttrType, FALSE, &uiRecCount, &pContext );
if ( dsStatus == eDSNoErr )
{
dsStatus = eDSInvalidName;
if ( uiRecCount == 1 )
{
dsStatus = dsGetRecordEntry( inSearchNodeRef, pTDataBuff, 1, &attrListRef, &pRecEntry );
if ( dsStatus == eDSNoErr )
{
(void)dsGetRecordNameFromEntry( pRecEntry, &pAcctName );
dsStatus = dsGetAttributeEntry( inSearchNodeRef, pTDataBuff, attrListRef, 1, &valueRef, &pAttrEntry );
if ( (dsStatus == eDSNoErr) && (pAttrEntry != NULL) )
{
dsStatus = dsGetAttributeValue( inSearchNodeRef, pTDataBuff, 1, valueRef, &pValueEntry );
if ( (dsStatus == eDSNoErr) && (pValueEntry != NULL) )
{
if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrMetaNodeLocation ) == 0 )
{
*outUserLocation = (char *)calloc( pValueEntry->fAttributeValueData.fBufferLength + 1, sizeof( char ) );
memcpy( *outUserLocation, pValueEntry->fAttributeValueData.fBufferData, pValueEntry->fAttributeValueData.fBufferLength );
done = TRUE;
}
(void)dsCloseAttributeValueList( valueRef );
}
(void)dsDeallocAttributeEntry( inSearchNodeRef, pAttrEntry );
pAttrEntry = NULL;
(void)dsCloseAttributeList( attrListRef );
}
if ( pRecEntry != NULL )
{
(void)dsDeallocRecordEntry( inSearchNodeRef, pRecEntry );
pRecEntry = NULL;
}
}
}
else
{
done = true;
if ( uiRecCount > 1 )
{
syslog( LOG_ERR, "cram_md5_auth: Duplicate users %s found in directory.", inUserID );
}
dsStatus = eDSAuthInvalidUserName;
}
}
} while ( (pContext != NULL) && (dsStatus == eDSNoErr) && (!done) );
if ( pContext != NULL )
{
(void)dsReleaseContinueData( inSearchNodeRef, pContext );
pContext = NULL;
}
(void)dsDataListDeallocate( inDirRef, pUserAttrType );
pUserAttrType = NULL;
}
(void)dsDataListDeallocate( inDirRef, pUserRecType );
pUserRecType = NULL;
}
(void)dsDataListDeAllocate( inDirRef, &tdlRecName, TRUE );
}
(void)dsDataBufferDeAllocate( inDirRef, pTDataBuff );
pTDataBuff = NULL;
}
if ( pAcctName != NULL )
{
free( pAcctName );
pAcctName = NULL;
}
return( dsStatus );
}
int sValidateResponse ( const char *inUserID, const char *inChallenge, const char *inResponse, const char *inAuthType, int validateType )
{
int iResult = -1;
tDirStatus dsStatus = eDSNoErr;
tDirReference dirRef = 0;
tDirNodeReference searchNodeRef = 0;
tDirNodeReference userNodeRef = 0;
tDataBuffer *pAuthBuff = NULL;
tDataBuffer *pStepBuff = NULL;
tDataNode *pAuthType = NULL;
char *userLoc = NULL;
unsigned long uiNameLen = 0;
unsigned long uiChalLen = 0;
unsigned long uiRespLen = 0;
unsigned long uiBuffSzie = 0;
unsigned long uiCurr = 0;
unsigned long uiLen = 0;
int logErrors = kLogErrors_disabled;
if (kValidate_User == validateType)
logErrors = kLogErrors_enabled;
if ( (inUserID == NULL) || (inChallenge == NULL) || (inResponse == NULL) || (inAuthType == NULL) )
{
return( -1 );
}
uiNameLen = strlen( inUserID );
uiChalLen = strlen( inChallenge );
uiRespLen = strlen( inResponse );
uiBuffSzie = uiNameLen + uiChalLen + uiRespLen + 32;
dsStatus = dsOpenDirService( &dirRef );
if ( dsStatus == eDSNoErr )
{
dsStatus = sGet_search_node( dirRef, &searchNodeRef );
if ( dsStatus == eDSNoErr )
{
dsStatus = sLook_up_user( dirRef, searchNodeRef, inUserID, &userLoc );
if ( dsStatus == eDSNoErr )
{
dsStatus = sOpen_user_node( dirRef, userLoc, &userNodeRef );
if ( dsStatus == eDSNoErr )
{
pAuthBuff = dsDataBufferAllocate( dirRef, uiBuffSzie );
if ( pAuthBuff != NULL )
{
pStepBuff = dsDataBufferAllocate( dirRef, 256 );
if ( pStepBuff != NULL )
{
pAuthType = dsDataNodeAllocateString( dirRef, inAuthType );
if ( pAuthType != NULL )
{
uiLen = uiNameLen;
memcpy( &(pAuthBuff->fBufferData[ uiCurr ]), &uiLen, sizeof( unsigned long ) );
uiCurr += sizeof( unsigned long );
memcpy( &(pAuthBuff->fBufferData[ uiCurr ]), inUserID, uiLen );
uiCurr += uiLen;
if (kValidate_User == validateType)
{
uiLen = uiChalLen;
memcpy( &(pAuthBuff->fBufferData[ uiCurr ]), &uiLen, sizeof( unsigned long ) );
uiCurr += sizeof( unsigned long );
memcpy( &(pAuthBuff->fBufferData[ uiCurr ]), inChallenge, uiLen );
uiCurr += uiLen;
uiLen = uiRespLen;
memcpy( &(pAuthBuff->fBufferData[ uiCurr ]), &uiLen, sizeof( unsigned long ) );
uiCurr += sizeof( unsigned long );
memcpy( &(pAuthBuff->fBufferData[ uiCurr ]), inResponse, uiLen );
uiCurr += uiLen;
}
pAuthBuff->fBufferLength = uiCurr;
dsStatus = dsDoDirNodeAuth( userNodeRef, pAuthType, true, pAuthBuff, pStepBuff, NULL );
if ( (kValidate_AuthMethod == validateType) && (eDSAuthFailed == dsStatus) )
dsStatus = eDSAuthMethodNotSupported;
switch ( dsStatus )
{
case eDSNoErr:
iResult = eDSNoErr;
break;
case eDSAuthNewPasswordRequired:
iResult = eDSNoErr;
break;
case eDSAuthPasswordExpired:
iResult = eDSNoErr;
break;
default:
iResult = dsStatus;
if (logErrors)
syslog( LOG_ERR, "cram_md5_auth: Authentication failed for user %s err=%d",inUserID,dsStatus);
break;
}
(void)dsDataNodeDeAllocate( dirRef, pAuthType );
pAuthType = NULL;
}
else
{
if (logErrors)
syslog( LOG_ERR, "cram_md5_auth: Authentication failed for user %s. Unable to allocate memory.", inUserID );
iResult = dsStatus;
}
(void)dsDataNodeDeAllocate( dirRef, pStepBuff );
pStepBuff = NULL;
}
else
{
if (logErrors)
syslog( LOG_ERR, "cram_md5_auth: Authentication failed for user %s. Unable to allocate memory.", inUserID );
iResult = dsStatus;
}
(void)dsDataNodeDeAllocate( dirRef, pAuthBuff );
pAuthBuff = NULL;
}
else
{
if (logErrors)
syslog( LOG_ERR, "cram_md5_auth: Authentication failed for user %s. Unable to allocate memory.", inUserID );
iResult = dsStatus;
}
(void)dsCloseDirNode( userNodeRef );
userNodeRef = 0;
}
else
{
if (logErrors)
syslog( LOG_ERR, "cram_md5_auth: Unable to open user directory node for user %s. (Open Directroy error: %d)", inUserID, dsStatus );
iResult = dsStatus;
}
}
else
{
if (logErrors)
syslog( LOG_ERR, "cram_md5_auth: Unable to find user %s. (Open Directroy error: %d)", inUserID, dsStatus );
iResult = dsStatus;
}
(void)dsCloseDirNode( searchNodeRef );
searchNodeRef = 0;
}
else
{
if (logErrors)
syslog( dsStatus, "cram_md5_auth: Unable to open directroy search node. (Open Directroy error: %d)", dsStatus );
iResult = dsStatus;
}
(void)dsCloseDirService( dirRef );
dirRef = 0;
}
else
{
if (logErrors)
syslog( LOG_ERR, "cram_md5_auth: Unable to open directroy. (Open Directroy error: %d)", dsStatus );
iResult = dsStatus;
}
return( iResult );
}
int authenticate_cram_md5 ( const char *inUserID, const char *inChallenge, const char *inResponse )
{
return( sValidateResponse( inUserID, inChallenge, inResponse, kDSStdAuthCRAM_MD5, kValidate_User ) );
}
int ds_supports_cram_md5 ( const char *inUserID )
{
if (eDSAuthMethodNotSupported == sValidateResponse( inUserID, "", "", kDSStdAuthCRAM_MD5, kValidate_AuthMethod ) )
return 0;
return 1;
}
int ConvertBytesToHexChars( const void* inValue, unsigned long inValueLen, void *destPtr, unsigned long destLen, unsigned long *destCharCount)
{
static const char* kHEXChars={ "0123456789abcdef" };
unsigned char* theDataPtr = (unsigned char*) inValue;
unsigned long copylen = inValueLen;
char *theString = (char *) destPtr;
unsigned char temp;
unsigned long count = 0;
if (NULL == destPtr || destLen < 2)
{
return 0;
}
if ( (inValueLen * 2) > destLen)
copylen = destLen / 2;
for (count = 0; count < copylen; count++)
{
temp = *theDataPtr++;
*theString++ = kHEXChars[temp >> 4];
*theString++ = kHEXChars[temp & 0xF];
}
if (destCharCount != NULL)
*destCharCount = copylen * 2;
return copylen;
}