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>
#include <membership.h>
#include <membershipPriv.h>
enum { kLogErrors_disabled = 0, kLogErrors_enabled = 1 };
enum { kValidate_AuthMethod = 0, kValidate_User = 1 };
#if 0
tDirStatus _od_auth_open_user_node(tDirReference inDirRef, const char *inUserLoc,
tDirNodeReference *outUserNodeRef);
tDirStatus _od_auth_get_search_node(tDirReference inDirRef,
tDirNodeReference *outSearchNodeRef)
tDirStatus _od_auth_lookup_user(tDirReference inDirRef,
tDirNodeReference inSearchNodeRef,
const char *inUserID,
char **outUserLocation);
int _od_auth_validate_response(const char *inUserID, const char *inChallenge,
const char *inResponse, const char *inAuthType,
int validateType);
int _od_auth_bytes_to_hex_chars(const void* inValue, unsigned long inValueLen,
void *destPtr, unsigned long destLen,
unsigned long *destCharCount);
#endif
int _od_auth_check_user_exists(const char *inUserID);
int od_auth_check_user_exists(const char* userName)
{
return( _od_auth_check_user_exists( userName ) );
return kFailed;
}
int od_auth_check_plain_password(const char* userName, const char* password)
{
if (CHECKPW_SUCCESS == checkpw(userName, password))
return kAuthenticated;
return kFailed;
}
int od_auth_supports_cram_md5(const char *inUserID)
{
int iResult = _od_auth_validate_response( inUserID, "", "",
kDSStdAuthCRAM_MD5,
kValidate_AuthMethod);
if (eDSAuthMethodNotSupported == iResult)
return 0;
return 1;
}
int od_auth_create_crammd5_challenge(char *outChallenge, int destsize)
{
int numchars = 0;
char randombytes[ 32 ];
unsigned long destChars = 0;
if (NULL != outChallenge)
outChallenge[0] = 0;
if (destsize < 5) return 0;
if (0 == RAND_bytes(randombytes, sizeof(randombytes) ) )
return 0;
numchars = _od_auth_bytes_to_hex_chars( randombytes, sizeof(randombytes), outChallenge, (unsigned long) destsize - 1, &destChars);
if (numchars != sizeof(randombytes) || destChars >= destsize) numchars = destChars = 0;
outChallenge[destChars] = 0; return numchars;
}
int od_auth_check_crammd5_response(const char *inUserID, const char *inChallenge,
const char *inResponse)
{
int iResult = _od_auth_validate_response( inUserID, inChallenge, inResponse,
kDSStdAuthCRAM_MD5,
kValidate_User );
return( iResult );
}
int od_auth_check_service_membership(const char* userName, const char* service)
{
syslog(LOG_USER | LOG_NOTICE, "%s: checking user \"%s\" access for service \"%s\"",
__PRETTY_FUNCTION__, userName, service);
int mbrErr = 0;
uuid_t user_uuid;
if (mbrErr = mbr_user_name_to_uuid(userName, user_uuid)){
syslog(LOG_ERR, "%s: mbr_user_name_to_uuid returns %s", __PRETTY_FUNCTION__, strerror(mbrErr));
return 0;
}
int isMember = 0;
mbrErr = mbr_check_service_membership(user_uuid, service, &isMember);
syslog(LOG_USER | LOG_NOTICE, "%s: mbr_check_service_membership returned %d", __PRETTY_FUNCTION__, mbrErr);
if (0 != mbrErr) {
if (mbrErr == ENOENT) syslog(LOG_USER | LOG_NOTICE, "%s: no access restrictions found", __PRETTY_FUNCTION__);
else
syslog(LOG_ERR, "%s: mbr_check_service_membership returns %s", __PRETTY_FUNCTION__, strerror(mbrErr));
return (mbrErr == ENOENT) ? 1 : 0;
}
syslog(LOG_ERR, "%s: user \"%s\" %s authorized to access service \"%s\"",
__PRETTY_FUNCTION__, userName, (1 == isMember ? "is" : "is not"), service);
return (1 == isMember) ? 1 : 0;
}
int _od_auth_bytes_to_hex_chars( 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;
}
tDirStatus _od_auth_open_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 );
free( pUserNode );
pUserNode = NULL;
}
return( dsStatus );
}
tDirStatus _od_auth_get_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 );
free( pDataList );
pDataList = NULL;
}
}
}
(void) dsDataBufferDeAllocate( inDirRef, pTDataBuff );
pTDataBuff = NULL;
}
return( dsStatus );
}
tDirStatus _od_auth_lookup_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 );
if (pUserAttrType != NULL) {
free(pUserAttrType);
pUserAttrType = NULL;
}
}
(void)dsDataListDeallocate( inDirRef, pUserRecType );
if (pUserRecType != NULL) {
free(pUserRecType);
pUserRecType = NULL;
}
}
(void)dsDataListDeallocate( inDirRef, &tdlRecName );
if (tdlRecName.fDataListHead != NULL) {
free(tdlRecName.fDataListHead);
tdlRecName.fDataListHead = NULL;
}
}
(void)dsDataBufferDeAllocate( inDirRef, pTDataBuff );
pTDataBuff = NULL;
}
if ( pAcctName != NULL ) {
free( pAcctName );
pAcctName = NULL;
}
if ( pValueEntry != NULL ) {
free( pValueEntry );
pValueEntry = NULL;
}
return( dsStatus );
}
int _od_auth_validate_response ( 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 = _od_auth_get_search_node( dirRef, &searchNodeRef );
if ( dsStatus == eDSNoErr ) {
dsStatus = _od_auth_lookup_user( dirRef, searchNodeRef, inUserID, &userLoc );
if ( dsStatus == eDSNoErr ) {
dsStatus = _od_auth_open_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 Directory error: %d)", inUserID, dsStatus );
iResult = dsStatus;
}
}
else {
if (logErrors)
syslog( LOG_ERR, "cram_md5_auth: Unable to find user %s. (Open Directory 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 Directory error: %d)", dsStatus );
iResult = dsStatus;
}
(void) dsCloseDirService( dirRef );
dirRef = 0;
}
else {
if (logErrors)
syslog( LOG_ERR, "cram_md5_auth: Unable to open directroy. (Open Directory error: %d)", dsStatus );
iResult = dsStatus;
}
if (userLoc != NULL) {
free(userLoc);
userLoc = NULL;
}
return( iResult );
}
int _od_auth_check_user_exists(const char *inUserID)
{
int iResult = 0;
tDirStatus dsStatus = eDSNoErr;
tDirReference dirRef = 0;
tDirNodeReference searchNodeRef = 0;
tDirNodeReference userNodeRef = 0;
char *userLoc = NULL;
unsigned long uiNameLen = 0;
unsigned long uiBuffSzie = 0;
int logErrors = kLogErrors_disabled;
if ( (inUserID == NULL) ) {
return( -1 );
}
uiNameLen = strlen( inUserID );
uiBuffSzie = uiNameLen + 32;
dsStatus = dsOpenDirService( &dirRef );
if ( dsStatus == eDSNoErr ) {
dsStatus = _od_auth_get_search_node( dirRef, &searchNodeRef );
if ( dsStatus == eDSNoErr ) {
dsStatus = _od_auth_lookup_user( dirRef, searchNodeRef, inUserID, &userLoc );
if ( dsStatus == eDSNoErr ) {
dsStatus = _od_auth_open_user_node( dirRef, userLoc, &userNodeRef );
if ( dsStatus == eDSNoErr )
iResult = 1; else {
if (logErrors)
syslog( LOG_ERR, "_od_auth_check_user_exists: Unable to open user directory node for user %s. (Open Directory error: %d)", inUserID, dsStatus );
iResult = dsStatus;
}
}
else {
if (logErrors)
syslog( LOG_ERR, "_od_auth_check_user_exists: Unable to find user %s. (Open Directory error: %d)", inUserID, dsStatus );
iResult = dsStatus;
}
(void)dsCloseDirNode( searchNodeRef );
searchNodeRef = 0;
}
else {
if (logErrors)
syslog( dsStatus, "_od_auth_check_user_exists: Unable to open directroy search node. (Open Directory error: %d)", dsStatus );
iResult = dsStatus;
}
(void)dsCloseDirService( dirRef );
dirRef = 0;
}
else {
if (logErrors)
syslog( LOG_ERR, "_od_auth_check_user_exists: Unable to open directroy. (Open Directory error: %d)", dsStatus );
iResult = dsStatus;
}
if (userLoc != NULL) {
free(userLoc);
userLoc = NULL;
}
return( iResult );
}