#include <string.h>
#include "buffer_unpackers.h"
#include "CDSAuthDefs.h"
#include "CDSLocalAuthHelper.h"
#include "CDSAuthParams.h"
#include "PrivateTypes.h"
#include "DSUtils.h"
#include "AuthHelperUtils.h"
#include "DirServiceMain.h"
CDSAuthParams::CDSAuthParams()
{
uiAuthMethod = kAuthUnknownMethod;
mAuthMethodStr = NULL;
pUserName = NULL;
pNewPassword = NULL;
pOldPassword = NULL;
pNTLMDigest = NULL;
ntlmDigestLen = 0;
pCramResponse = NULL;
cramResponseLen = 0;
pSambaName = NULL;
pDomain = NULL;
pAdminUser = NULL;
pAdminPassword = NULL;
PeerC16 = NULL;
dataList = NULL;
path = NULL;
hashLength = kHashTotalLength;
hashesLengthFromFile = 0;
secureHashNode = NULL;
itemCount = 0;
nativeAttrType = NULL;
policyStr = NULL;
policyStrLen = 0;
keySize = 0;
challenge = NULL;
apopResponse = NULL;
aaData = NULL;
aaDataLocalCacheUser = NULL;
serviceInfoDict = NULL;
mPostAuthEvent = false;
bzero(&modDateOfPassword, sizeof(modDateOfPassword));
bzero(&modDateAssist, sizeof(modDateAssist));
bzero(&globalAccess, sizeof(globalAccess));
bzero(&globalMoreAccess, sizeof(globalMoreAccess));
bzero(&digestContext, sizeof(digestContext));
ZeroHashes();
}
CDSAuthParams::~CDSAuthParams()
{
DSFreeString( mAuthMethodStr );
DSFreeString( path );
DSFreeString( policyStr );
if ( nativeAttrType != NULL )
{
delete nativeAttrType;
nativeAttrType = NULL;
}
if (dataList != NULL)
{
dsDataListDeallocatePriv(dataList);
free(dataList);
dataList = NULL;
}
DSFreeString( pUserName );
if ( pNewPassword != NULL )
{
bzero(pNewPassword, strlen(pNewPassword));
free( pNewPassword );
pNewPassword = NULL;
}
if ( pOldPassword != NULL )
{
bzero(pOldPassword, strlen(pOldPassword));
free( pOldPassword );
pOldPassword = NULL;
}
DSFree( PeerC16 );
DSFree( pNTLMDigest );
DSFreeString( pSambaName );
DSFreeString( pDomain );
DSFreeString( pAdminUser );
if ( pAdminPassword != NULL )
{
bzero(pAdminPassword, strlen(pAdminPassword));
free( pAdminPassword );
pAdminPassword = NULL;
}
digest_dispose( &digestContext );
DSFreeString( challenge );
DSFreeString( apopResponse );
DSFree( pCramResponse );
DSFreeString( aaData );
DSFreeString( aaDataLocalCacheUser );
DSCFRelease( serviceInfoDict );
ZeroHashes();
}
void
CDSAuthParams::ZeroHashes( void )
{
bzero(P21, kHashShadowKeyLength);
bzero(C8, kHashShadowChallengeLength);
bzero(P24, kHashShadowResponseLength);
bzero(P24Input, kHashShadowResponseLength);
bzero(hashes, kHashTotalLength);
bzero(generatedHashes, kHashTotalLength);
bzero(secureHash, kHashSecureLength);
bzero(C16, sizeof(C16));
bzero(GeneratedNTLM, sizeof(GeneratedNTLM));
bzero(MSCHAP2Response, sizeof(MSCHAP2Response));
}
tDirStatus
CDSAuthParams::LoadParamsForAuthMethod(
tDataNodePtr inAuthMethod,
tDataBufferPtr inAuthData,
tDataBufferPtr inAuthStepData )
{
tDirStatus siResult = dsGetAuthMethodEnumValue( inAuthMethod, &uiAuthMethod );
if ( siResult != eDSNoErr && siResult != eDSAuthMethodNotSupported )
return siResult;
mAuthMethodStr = strdup( inAuthMethod->fBufferData );
siResult = ExtractServiceInfo( inAuthStepData );
if ( siResult != eDSNoErr )
return siResult;
switch( uiAuthMethod )
{
case kAuthPPS:
mPostAuthEvent = true;
siResult = (tDirStatus)Get2FromBuffer( inAuthData, NULL, &pUserName, &challenge, NULL );
break;
case kAuthDIGEST_MD5:
mPostAuthEvent = true;
siResult = (tDirStatus)UnpackDigestBuffer( inAuthData, &pUserName, &digestContext );
break;
case kAuthCRAM_MD5:
mPostAuthEvent = true;
siResult = (tDirStatus)UnpackCramBuffer( inAuthData, &pUserName, &challenge, &pCramResponse,
&cramResponseLen );
break;
case kAuthAPOP:
mPostAuthEvent = true;
siResult = (tDirStatus)UnpackAPOPBuffer( inAuthData, &pUserName, &challenge, &apopResponse );
break;
case kAuthSMB_NT_Key:
mPostAuthEvent = true;
siResult = (tDirStatus)UnpackSambaBuffer( inAuthData, &pUserName, C8, P24Input );
break;
case kAuthSMB_LM_Key:
mPostAuthEvent = true;
siResult = (tDirStatus)UnpackSambaBuffer( inAuthData, &pUserName, C8, P24Input );
break;
case kAuthNTLMv2:
mPostAuthEvent = true;
siResult = (tDirStatus)UnpackNTLMv2Buffer( inAuthData, &pUserName, C8, &pNTLMDigest, &ntlmDigestLen,
&pSambaName, &pDomain );
break;
case kAuthMSCHAP2:
mPostAuthEvent = true;
if ( inAuthStepData == NULL )
return( eDSNullAuthStepData );
if ( inAuthStepData->fBufferSize < 4 + MS_AUTH_RESPONSE_LENGTH )
return( eDSBufferTooSmall );
siResult = (tDirStatus)UnpackMSCHAPv2Buffer( inAuthData, &pUserName, C16, &PeerC16, &pNTLMDigest,
&ntlmDigestLen, &pSambaName );
break;
case kAuthVPN_PPTPMasterKeys:
if ( inAuthStepData == NULL )
return( eDSNullAuthStepData );
siResult = (tDirStatus)UnpackMPPEKeyBuffer( inAuthData, &pUserName, P24Input, &keySize );
if ( inAuthStepData->fBufferSize < (unsigned long)(8 + keySize*2) )
return( eDSBufferTooSmall );
break;
case kAuthSMBWorkstationCredentialSessionKey:
if ( inAuthStepData == NULL )
return( eDSNullAuthStepData );
siResult = GetNameAndDataFromBuffer( inAuthData, &dataList, &pUserName, &pNTLMDigest, &ntlmDigestLen, &itemCount );
if ( inAuthStepData->fBufferSize < (unsigned long)(sizeof(UInt32) + 8) )
return( eDSBufferTooSmall );
break;
case kAuthSecureHash:
mPostAuthEvent = true;
dataList = dsAuthBufferGetDataListAllocPriv(inAuthData);
if ( dataList == NULL ) return( eDSInvalidBuffFormat );
if ( dsDataListGetNodeCountPriv(dataList) != 2 ) return( eDSInvalidBuffFormat );
pUserName = dsDataListGetNodeStringPriv(dataList, 1);
if ( pUserName == NULL ) return( eDSInvalidBuffFormat );
if ( strlen(pUserName) < 1 ) return( eDSInvalidBuffFormat );
siResult = dsDataListGetNodePriv(dataList, 2, &secureHashNode);
if ( secureHashNode == NULL ) return( eDSInvalidBuffFormat );
if ( secureHashNode->fBufferLength != kHashSaltedSHA1Length ) return( eDSInvalidBuffFormat);
if ( siResult != eDSNoErr ) return( eDSInvalidBuffFormat );
memmove(secureHash, ((tDataBufferPriv*)secureHashNode)->fBufferData, secureHashNode->fBufferLength);
break;
case kAuthWriteSecureHash:
dataList = dsAuthBufferGetDataListAllocPriv(inAuthData);
if ( dataList == NULL ) return( eDSInvalidBuffFormat );
if ( dsDataListGetNodeCountPriv(dataList) != 2 ) return( eDSInvalidBuffFormat );
pUserName = dsDataListGetNodeStringPriv(dataList, 1);
if ( pUserName == NULL ) return( eDSInvalidBuffFormat );
if ( strlen(pUserName) < 1 ) return( eDSInvalidBuffFormat );
siResult = dsDataListGetNodePriv(dataList, 2, &secureHashNode);
if ( secureHashNode == NULL ) return( eDSInvalidBuffFormat );
if ( secureHashNode->fBufferLength != kHashSaltedSHA1Length ) return( eDSInvalidBuffFormat);
if ( siResult != eDSNoErr ) return( eDSInvalidBuffFormat );
memmove(secureHash, ((tDataBufferPriv*)secureHashNode)->fBufferData, secureHashNode->fBufferLength);
break;
case kAuthReadSecureHash:
if ( inAuthStepData == NULL ) return( eDSNullAuthStepData );
dataList = dsAuthBufferGetDataListAllocPriv(inAuthData);
if ( dataList == NULL ) return( eDSInvalidBuffFormat );
if ( dsDataListGetNodeCountPriv(dataList) != 1 ) return( eDSInvalidBuffFormat );
pUserName = dsDataListGetNodeStringPriv(dataList, 1);
if ( pUserName == NULL ) return( eDSInvalidBuffFormat );
if ( strlen(pUserName) < 1 ) return( eDSInvalidBuffFormat );
break;
case kAuthSetPasswd:
case kAuthSetPasswdAsRoot:
siResult = (tDirStatus)Get2FromBuffer( inAuthData, &dataList, &pUserName, &pNewPassword, &itemCount );
if ( (pNewPassword != nil) && (strlen(pNewPassword) >= kHashRecoverableLength) )
return ( eDSAuthPasswordTooLong );
if ( siResult == eDSNoErr )
{
if ( uiAuthMethod == kAuthSetPasswd )
{
if ( itemCount != 4 )
return( eDSInvalidBuffFormat );
pAdminUser = dsDataListGetNodeStringPriv( dataList, 3 );
if ( pAdminUser == NULL ) return( eDSInvalidBuffFormat );
pAdminPassword = dsDataListGetNodeStringPriv( dataList, 4 );
if ( pAdminPassword == NULL ) return( eDSInvalidBuffFormat );
}
else if ( uiAuthMethod == kAuthSetPasswdAsRoot && itemCount != 2 )
return( eDSInvalidBuffFormat );
}
break;
case kAuthSetPolicyAsRoot:
siResult = (tDirStatus)Get2FromBuffer(inAuthData, &dataList, &pUserName, &pNewPassword, &itemCount );
if ( (pNewPassword != nil) && (strlen(pNewPassword) >= kHashRecoverableLength) )
return ( eDSAuthPasswordTooLong );
if ( siResult != eDSNoErr )
return( siResult );
if ( itemCount != 2 || pNewPassword == NULL || pNewPassword[0] == '\0' )
return( eDSInvalidBuffFormat );
break;
case kAuthChangePasswd:
siResult = (tDirStatus)Get2FromBuffer(inAuthData, &dataList, &pUserName, &pOldPassword, &itemCount );
if ( (pOldPassword != nil) && (strlen(pOldPassword) >= kHashRecoverableLength) )
return ( eDSAuthPasswordTooLong );
if ( siResult != eDSNoErr )
return( siResult );
if ( itemCount != 3 )
return( eDSInvalidBuffFormat );
pNewPassword = dsDataListGetNodeStringPriv(dataList, 3);
if ( pNewPassword == NULL ) return( eDSInvalidBuffFormat );
if ( (pNewPassword != nil) && (strlen(pNewPassword) >= kHashRecoverableLength) )
return ( eDSAuthPasswordTooLong );
break;
case kAuthSetShadowHashWindows:
case kAuthSetShadowHashSecure:
case kAuthNativeClearTextOK:
case kAuthNativeNoClearText:
case kAuthNativeRetainCredential:
mPostAuthEvent = true;
siResult = (tDirStatus)Get2FromBuffer(inAuthData, &dataList, &pUserName, &pOldPassword, &itemCount );
break;
case kAuthSetPasswdCheckAdmin:
{
char *pUserToChangeName = NULL;
bool modifyingSelf;
dataList = dsAuthBufferGetDataListAllocPriv(inAuthData);
if ( dataList == NULL ) return( eDSInvalidBuffFormat );
itemCount = dsDataListGetNodeCountPriv(dataList);
if ( itemCount != 4 ) return( eDSInvalidBuffFormat );
pUserName = dsDataListGetNodeStringPriv(dataList, 3);
if ( pUserName == NULL ) return( eDSInvalidBuffFormat );
if ( strlen(pUserName) < 1 ) return( eDSInvalidBuffFormat );
pOldPassword = dsDataListGetNodeStringPriv(dataList, 4);
if ( pOldPassword == NULL )
return( eDSInvalidBuffFormat );
if ( strlen(pOldPassword) < 1 )
return( eDSInvalidBuffFormat );
pUserToChangeName = dsDataListGetNodeStringPriv(dataList, 1);
if ( pUserToChangeName == NULL )
return( eDSInvalidBuffFormat );
if ( strlen(pUserToChangeName) < 1 ) {
free( pUserToChangeName );
return( eDSInvalidBuffFormat );
}
modifyingSelf = (pUserToChangeName != NULL) && (pUserName != NULL) && (strcmp(pUserToChangeName,
pUserName) == 0);
DSFreeString( pUserToChangeName );
}
break;
case kAuthGetPolicy:
case kAuthGetEffectivePolicy:
if ( inAuthStepData == NULL ) return( eDSNullAuthStepData );
inAuthStepData->fBufferLength = 0;
dataList = dsAuthBufferGetDataListAllocPriv( inAuthData );
if ( dataList == NULL ) return( eDSInvalidBuffFormat );
itemCount = dsDataListGetNodeCountPriv( dataList );
if ( (uiAuthMethod == kAuthGetPolicy && itemCount != 3) || (uiAuthMethod == kAuthGetEffectivePolicy && itemCount != 1) )
return( eDSInvalidBuffFormat );
pUserName = dsDataListGetNodeStringPriv(dataList, (uiAuthMethod == kAuthGetPolicy ? 3 : 1));
if ( pUserName == NULL ) return( eDSInvalidBuffFormat );
if ( strlen(pUserName) < 1 ) return( eDSInvalidBuffFormat );
break;
case kAuthSetPolicy:
dataList = dsAuthBufferGetDataListAllocPriv(inAuthData);
if ( dataList == NULL ) return( eDSInvalidBuffFormat );
itemCount = dsDataListGetNodeCountPriv(dataList);
if ( itemCount != 4 ) return( eDSInvalidBuffFormat );
pAdminUser = dsDataListGetNodeStringPriv(dataList, 1);
if ( DSIsStringEmpty(pAdminUser) )
{
DSFreeString( pAdminUser );
}
else
{
pOldPassword = dsDataListGetNodeStringPriv(dataList, 2);
}
pUserName = dsDataListGetNodeStringPriv(dataList, 3);
if ( pUserName == NULL || pUserName[0] == '\0' )
return( eDSInvalidBuffFormat );
pNewPassword = dsDataListGetNodeStringPriv(dataList, 4);
if ( pNewPassword == NULL || pNewPassword[0] == '\0' )
return( eDSInvalidBuffFormat );
break;
case kAuthGetGlobalPolicy:
if ( inAuthStepData == NULL )
return( eDSNullAuthStepData );
inAuthStepData->fBufferLength = 0;
break;
case kAuthSetGlobalPolicy:
break;
case kAuthSetLMHash:
siResult = GetNameAndDataFromBuffer( inAuthData, &dataList, &pUserName, &pNTLMDigest, &ntlmDigestLen, &itemCount );
break;
case kAuthNTSetWorkstationPasswd:
case kAuthSMB_NTUserSessionKey:
siResult = GetNameAndDataFromBuffer( inAuthData, &dataList, &pUserName, &pNTLMDigest, &ntlmDigestLen, &itemCount );
break;
case kAuthMSLMCHAP2ChangePasswd:
siResult = (tDirStatus)Get2FromBuffer( inAuthData, &dataList, &pUserName, &pOldPassword, &itemCount );
if ( siResult != eDSNoErr )
return( siResult );
if ( itemCount != 3 )
return( eDSInvalidBuffFormat );
siResult = dsDataListGetNodePriv( dataList, 3, &secureHashNode );
if ( siResult != eDSNoErr || secureHashNode == NULL )
return( eDSInvalidBuffFormat );
ntlmDigestLen = secureHashNode->fBufferLength;
pNTLMDigest = (uint8_t *)malloc( ntlmDigestLen );
if ( pNTLMDigest == NULL )
return( eMemoryError );
memmove( pNTLMDigest, ((tDataBufferPriv*)secureHashNode)->fBufferData, ntlmDigestLen );
break;
case kAuthSetCertificateHashAsRoot:
siResult = (tDirStatus)Get2FromBuffer( inAuthData, &dataList, &pUserName, &pNewPassword, &itemCount );
if ( siResult != eDSNoErr )
return( siResult );
if ( itemCount != 2 )
return( eDSInvalidBuffFormat );
break;
default:
break;
}
return siResult;
}
void
CDSAuthParams::PostEvent( tDirStatus inAuthResult )
{
if ( mPostAuthEvent )
{
CFStringRef eventType = (inAuthResult == eDSNoErr) ? CFSTR("auth.success") : CFSTR("auth.failure");
CFMutableDictionaryRef eventDict = dsCreateEventLogDict( eventType, pUserName, serviceInfoDict );
if ( eventDict != NULL ) {
dsPostEvent( eventType, eventDict );
CFRelease( eventDict );
}
}
}
CFMutableDictionaryRef
CDSAuthParams::DictionaryFromAuthItems( void )
{
CFMutableDictionaryRef rootItemDict;
rootItemDict = CFDictionaryCreateMutable(
kCFAllocatorDefault,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks );
CFMutableDictionaryRef authenticatorDict;
authenticatorDict = CFDictionaryCreateMutable(
kCFAllocatorDefault,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks );
CFMutableDictionaryRef targetUserDict;
targetUserDict = CFDictionaryCreateMutable(
kCFAllocatorDefault,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks );
CFDictionarySetValue( rootItemDict, CFSTR("Authenticator"), authenticatorDict );
CFDictionarySetValue( rootItemDict, CFSTR("TargetUser"), targetUserDict );
if ( pAdminUser != NULL ) {
CFStringRef adminName = CFStringCreateWithCString( kCFAllocatorDefault, pAdminUser, kCFStringEncodingUTF8 );
CFDictionarySetValue( authenticatorDict, CFSTR("name"), adminName );
CFRelease( adminName );
}
if ( pAdminPassword != NULL ) {
CFStringRef adminPassword = CFStringCreateWithCString( kCFAllocatorDefault, pAdminPassword, kCFStringEncodingUTF8 );
CFDictionarySetValue( authenticatorDict, CFSTR("password"), adminPassword );
CFRelease( adminPassword );
}
CFMutableDictionaryRef lServiceInfoDict = NULL;
if ( serviceInfoDict != NULL ) {
lServiceInfoDict = CFDictionaryCreateMutableCopy(
kCFAllocatorDefault,
0,
serviceInfoDict );
CFDictionarySetValue( rootItemDict, CFSTR("ServiceInformation"), lServiceInfoDict );
CFRelease( lServiceInfoDict );
}
if ( pUserName != NULL ) {
CFStringRef userName = CFStringCreateWithCString( kCFAllocatorDefault, pUserName, kCFStringEncodingUTF8 );
CFDictionarySetValue( targetUserDict, CFSTR("name"), userName );
CFRelease( userName );
}
if ( pNewPassword != NULL ) {
CFStringRef userNewPassword = CFStringCreateWithCString( kCFAllocatorDefault, pNewPassword, kCFStringEncodingUTF8 );
CFDictionarySetValue( targetUserDict, CFSTR("NewPassword"), userNewPassword );
CFRelease( userNewPassword );
}
if ( pOldPassword != NULL ) {
CFStringRef userOldPassword = CFStringCreateWithCString( kCFAllocatorDefault, pOldPassword, kCFStringEncodingUTF8 );
CFDictionarySetValue( targetUserDict, CFSTR("OldPassword"), userOldPassword );
CFRelease( userOldPassword );
}
char *xmlDataStr = NULL;
CFDataRef xmlData = NULL;
CFMutableDictionaryRef xmlDataDict = NULL;
CFStringRef errorString = NULL;
if ( policyStr != NULL ) {
if ( ConvertGlobalSpaceDelimitedPolicyToXML(policyStr, &xmlDataStr) == 0 ) {
xmlData = CFDataCreate( kCFAllocatorDefault, (UInt8 *)xmlDataStr, strlen(xmlDataStr) );
xmlDataDict = (CFMutableDictionaryRef) CFPropertyListCreateFromXMLData( kCFAllocatorDefault, xmlData,
kCFPropertyListMutableContainersAndLeaves, &errorString );
CFDictionarySetValue( targetUserDict, CFSTR("policy"), xmlDataDict );
CFRelease( xmlDataDict );
}
}
CFRelease( authenticatorDict );
CFRelease( targetUserDict );
return rootItemDict;
}
void
CDSAuthParams::SetParamsFromDictionary( CFDictionaryRef inKeyedAuthItems )
{
}
tDirStatus CDSAuthParams::ExtractServiceInfo( tDataBufferPtr inAuthStepData )
{
tDirStatus status = eDSNoErr;
char *plistStr = NULL;
int plistStrLen = 0;
CFDataRef plistData = NULL;
CFDictionaryRef plistDict = NULL;
CFDictionaryRef infoDict = NULL;
CFDataRef infoData = NULL;
CFStringRef errorString = NULL;
DSCFRelease( serviceInfoDict );
do
{
if ( GetUserNameFromAuthBuffer(inAuthStepData, 1, &plistStr, &plistStrLen) == eDSNoErr && plistStr != NULL )
{
plistData = CFDataCreate( kCFAllocatorDefault, (const unsigned char *)plistStr, plistStrLen );
if ( plistData == NULL )
return( eMemoryError );
plistDict = (CFDictionaryRef) CFPropertyListCreateFromXMLData( kCFAllocatorDefault, plistData,
kCFPropertyListImmutable, &errorString );
if ( plistDict == NULL || CFGetTypeID(plistDict) != CFDictionaryGetTypeID() ) {
status = eDSInvalidBuffFormat;
break;
}
if ( CFDictionaryGetValueIfPresent(plistDict, CFSTR("ServiceInformation"), (const void **)&infoDict) && infoDict != NULL )
{
if ( CFGetTypeID(infoDict) != CFDictionaryGetTypeID() ) {
status = eDSInvalidBuffFormat;
break;
}
serviceInfoDict = (CFDictionaryRef) CFRetain( infoDict );
}
}
}
while ( 0 );
DSCFRelease( plistDict );
DSCFRelease( plistData );
DSCFRelease( errorString );
DSCFRelease( infoData );
DSFreeString( plistStr );
return status;
}