CDSPluginUtils.cpp [plain text]
#include "CDSPluginUtils.h"
#include "DSUtils.h"
#include "CLog.h"
#include <DirectoryServiceCore/ServerModuleLib.h>
#include <DirectoryServiceCore/DSLThread.h>
#include <CommonCrypto/CommonCryptor.h>
#include <servers/bootstrap.h>
#include <syslog.h>
#include <mach/mach_error.h>
#include <mach/mach.h>
#include "SMBAuth.h"
#include <DirectoryService/DirServicesConstPriv.h>
#include <notify.h>
const char* CStrFromCFString( CFStringRef inCFStr, char** ioCStr, size_t* ioCStrSize, bool* outCStrAllocated )
{
size_t cStrSize = (ioCStrSize ? *ioCStrSize : 0);
if ( outCStrAllocated != NULL )
*outCStrAllocated = false;
const char* cStrPtr = CFStringGetCStringPtr( inCFStr, kCFStringEncodingUTF8 );
if ( cStrPtr != NULL )
return cStrPtr;
CFIndex maxCStrLen = CFStringGetMaximumSizeForEncoding( CFStringGetLength(inCFStr), kCFStringEncodingUTF8 ) + 1;
if ( (size_t)maxCStrLen > cStrSize )
{
if( *ioCStr != NULL )
free( *ioCStr );
cStrSize = maxCStrLen;
*ioCStr = (char*)malloc( cStrSize );
if ( ioCStrSize != NULL )
*ioCStrSize = cStrSize;
if( outCStrAllocated != NULL )
*outCStrAllocated = true;
}
if( !CFStringGetCString( inCFStr, *ioCStr, cStrSize, kCFStringEncodingUTF8 ) )
{
DbgLog( kLogPlugin, "CStrFromCFString(): CFStringGetCString() failed!" );
return NULL;
}
return *ioCStr;
}
void CFDebugLog( SInt32 lType, const char* format, ... )
{
va_list ap;
va_start( ap, format );
CFDebugLogV( lType, format, ap );
va_end( ap );
}
void CFDebugLogV( SInt32 lType, const char* format, va_list ap )
{
CFStringRef formatString = ::CFStringCreateWithCString( NULL, format, kCFStringEncodingUTF8 );
CFStringRef logString = ::CFStringCreateWithFormatAndArguments( NULL, NULL, formatString, ap );
CFMutableStringRef mutableLogString = ::CFStringCreateMutableCopy( NULL, 0, logString );
CFStringFindAndReplace( mutableLogString, CFSTR( "%" ), CFSTR( "<percent>" ), CFRangeMake( 0, CFStringGetLength( mutableLogString ) ), 0 );
const char *dbgStr;
char* cStr = NULL;
size_t cStrSize = 0;
CFArrayRef dstrArray = CFStringCreateArrayBySeparatingStrings(NULL, mutableLogString, CFSTR("\n"));
if ( dstrArray != NULL )
{
CFIndex aryCount = CFArrayGetCount( dstrArray );
CFIndex index;
CFStringRef lineString;
for ( index = 0; index < aryCount; index++ )
{
lineString = (CFStringRef)CFArrayGetValueAtIndex( dstrArray, index );
dbgStr = CStrFromCFString( lineString, &cStr, &cStrSize, NULL );
DbgLog( lType, dbgStr, NULL );
}
DSCFRelease( dstrArray );
}
DSFreeString( cStr );
DSCFRelease( logString );
DSCFRelease( formatString );
DSCFRelease( mutableLogString );
}
SInt32 PWOpenDirNode( tDirNodeReference fDSRef, char *inNodeName, tDirNodeReference *outNodeRef )
{
SInt32 error = eDSNoErr;
SInt32 error2 = eDSNoErr;
tDataList *pDataList = nil;
pDataList = ::dsBuildFromPathPriv( inNodeName, "/" );
if ( pDataList != nil )
{
error = ::dsOpenDirNode( fDSRef, pDataList, outNodeRef );
error2 = ::dsDataListDeallocatePriv( pDataList );
free( pDataList );
}
return( error );
}
bool DoesThisMatch ( const char *inString,
const char *inPatt,
tDirPatternMatch inHow )
{
bool bOutResult = false;
CFMutableStringRef strRef = CFStringCreateMutable(NULL, 0);
CFMutableStringRef patRef = CFStringCreateMutable(NULL, 0);
CFRange range;
if ( (inString == nil) || (inPatt == nil) || (strRef == nil) || (patRef == nil) )
{
return( false );
}
CFStringAppendCString( strRef, inString, kCFStringEncodingUTF8 );
CFStringAppendCString( patRef, inPatt, kCFStringEncodingUTF8 );
if ( (inHow >= eDSiExact) && (inHow <= eDSiRegularExpression) )
{
CFStringUppercase( strRef, NULL );
CFStringUppercase( patRef, NULL );
}
switch ( inHow )
{
case eDSExact:
case eDSiExact:
{
if ( CFStringCompare( strRef, patRef, 0 ) == kCFCompareEqualTo )
{
bOutResult = true;
}
}
break;
case eDSStartsWith:
case eDSiStartsWith:
{
if ( CFStringHasPrefix( strRef, patRef ) )
{
bOutResult = true;
}
}
break;
case eDSEndsWith:
case eDSiEndsWith:
{
if ( CFStringHasSuffix( strRef, patRef ) )
{
bOutResult = true;
}
}
break;
case eDSContains:
case eDSiContains:
{
range = CFStringFind( strRef, patRef, 0 );
if ( range.location != kCFNotFound )
{
bOutResult = true;
}
}
break;
case eDSLessThan:
case eDSiLessThan:
{
if ( CFStringCompare( strRef, patRef, 0 ) == kCFCompareLessThan )
{
bOutResult = true;
}
}
break;
case eDSGreaterThan:
case eDSiGreaterThan:
{
if ( CFStringCompare( strRef, patRef, 0 ) == kCFCompareGreaterThan )
{
bOutResult = true;
}
}
break;
case eDSLessEqual:
case eDSiLessEqual:
{
if ( CFStringCompare( strRef, patRef, 0 ) != kCFCompareGreaterThan )
{
bOutResult = true;
}
}
break;
case eDSGreaterEqual:
case eDSiGreaterEqual:
{
if ( CFStringCompare( strRef, patRef, 0 ) != kCFCompareLessThan )
{
bOutResult = true;
}
}
break;
default:
break;
}
CFRelease( strRef );
strRef = nil;
CFRelease( patRef );
patRef = nil;
return( bOutResult );
}
tDirStatus MSCHAPv2ChangePass(
const char *inUsername,
const uint8_t *inLMHash,
const char *inEncoding,
const uint8_t *inData,
UInt32 inDataLen,
uint8_t **outPassword,
UInt32 *outPasswordLen )
{
tDirStatus status = eDSNoErr;
int result = -1;
UInt32 pwLen = 0;
UInt32 encodeVal = -1;
CCCryptorStatus ccStatus = kCCSuccess;
size_t dataOutMoved = 0;
char pwDataStr[1024];
UInt8 data[1024];
ccStatus = CCCrypt( kCCDecrypt, kCCAlgorithmRC4, 0, inLMHash, 16, NULL, inData, inDataLen,
(uint8_t *)pwDataStr, sizeof(pwDataStr), &dataOutMoved );
if ( ccStatus != kCCSuccess )
return eDSAuthFailed;
try
{
pwLen = (UInt32) LittleEndianCharsToInt32( &pwDataStr[512] );
if ( pwLen > 512 )
throw( (tDirStatus)eDSAuthPasswordTooLong );
if ( pwLen == 0 )
throw( (tDirStatus)eDSAuthPasswordTooShort );
memcpy( data, pwDataStr + 512 - pwLen, pwLen );
data[pwLen] = '\0';
data[pwLen + 1] = '\0';
sscanf( inEncoding, "%lu", &encodeVal );
if ( encodeVal == 0 && strcmp( inEncoding, "0" ) != 0 )
throw( (tDirStatus)eDSInvalidBuffFormat );
result = FALSE;
switch ( encodeVal )
{
case 0:
strcpy( pwDataStr, (char *)data );
result = TRUE;
break;
case 1:
LittleEndianUnicodeToUnicode((u_int16_t *)data, pwLen/2, (u_int16_t *)data);
CFStringRef pwString = CFStringCreateWithCharacters( kCFAllocatorDefault, (UniChar *)data, pwLen/2 );
if ( pwString != NULL )
{
result = CFStringGetCString( pwString, pwDataStr, sizeof(pwDataStr), kCFStringEncodingUTF8 );
CFRelease( pwString );
}
break;
default:
result = FALSE;
}
if ( result == FALSE )
throw( (tDirStatus)eDSAuthFailed );
*outPasswordLen = strlen( pwDataStr );
*outPassword = (uint8_t *)strdup( pwDataStr );
}
catch ( tDirStatus catchStatus )
{
status = catchStatus;
}
bzero( pwDataStr, sizeof(pwDataStr) );
return status;
}
char *GetLocalKDCRealm( void )
{
char *theRealmStr = NULL;
tDirStatus siResult = eDSNoErr;
tDirReference dsRef = 0;
tDataBufferPtr dataBuffer = dsDataBufferAllocatePriv( 1024 );
UInt32 nodeCount = 0;
tContextData context = 0;
tDataListPtr nodeName = NULL;
tDirNodeReference localNodeRef = 0;
tDataListPtr recName = NULL;
tDataListPtr recType = NULL;
tDataListPtr attrTypes = NULL;
UInt32 recCount = 1;
tAttributeListRef attrListRef = 0;
tRecordEntryPtr pRecEntry = NULL;
tAttributeValueListRef valueRef = 0;
tAttributeEntryPtr pAttrEntry = NULL;
tAttributeValueEntryPtr pValueEntry = NULL;
siResult = dsOpenDirService( &dsRef );
if ( siResult != eDSNoErr )
return NULL;
siResult = dsFindDirNodes( dsRef, dataBuffer, NULL, eDSLocalNodeNames, &nodeCount, &context );
if ( siResult != eDSNoErr || nodeCount == 0 )
goto bail;
siResult = dsGetDirNodeName( dsRef, dataBuffer, 1, &nodeName );
if ( siResult != eDSNoErr )
goto bail;
siResult = dsOpenDirNode( dsRef, nodeName, &localNodeRef );
if ( siResult != eDSNoErr )
goto bail;
recName = dsBuildListFromStringsPriv( "KerberosKDC", NULL );
recType = dsBuildListFromStringsPriv( kDSStdRecordTypeConfig, NULL );
attrTypes = dsBuildListFromStringsPriv( kDS1AttrDistinguishedName, NULL );
do
{
siResult = dsGetRecordList( localNodeRef, dataBuffer, recName, eDSExact, recType, attrTypes, false, &recCount,
&context );
if ( siResult == eDSBufferTooSmall )
{
UInt32 bufSize = dataBuffer->fBufferSize;
dsDataBufferDeallocatePriv( dataBuffer );
dataBuffer = dsDataBufferAllocatePriv( bufSize * 2 );
}
}
while ( siResult == eDSBufferTooSmall || ((siResult == eDSNoErr) && (recCount == 0) && (context != 0)) );
if ( siResult == eDSNoErr && recCount > 0 )
{
siResult = dsGetRecordEntry( localNodeRef, dataBuffer, 1, &attrListRef, &pRecEntry );
if ( siResult == eDSNoErr && pRecEntry != NULL )
{
siResult = dsGetAttributeEntry( localNodeRef, dataBuffer, attrListRef, 1, &valueRef, &pAttrEntry );
if ( siResult == eDSNoErr && pAttrEntry->fAttributeValueCount > 0 )
{
siResult = dsGetAttributeValue( localNodeRef, dataBuffer, 1, valueRef, &pValueEntry );
if ( siResult == eDSNoErr )
theRealmStr = dsCStrFromCharacters( pValueEntry->fAttributeValueData.fBufferData,
pValueEntry->fAttributeValueData.fBufferLength );
if ( pValueEntry != NULL )
dsDeallocAttributeValueEntry( dsRef, pValueEntry );
}
dsCloseAttributeValueList( valueRef );
if ( pAttrEntry != NULL )
dsDeallocAttributeEntry( dsRef, pAttrEntry );
}
dsCloseAttributeList(attrListRef);
if ( pRecEntry != NULL )
dsDeallocRecordEntry( dsRef, pRecEntry );
}
bail:
if ( recName != NULL ) {
dsDataListDeallocatePriv( recName );
free( recName );
}
if ( recType != NULL ) {
dsDataListDeallocatePriv( recType );
free( recType );
}
if ( attrTypes != NULL ) {
dsDataListDeallocatePriv( attrTypes );
free( attrTypes );
}
if ( nodeName != NULL ) {
dsDataListDeallocatePriv( nodeName );
free( nodeName );
}
if ( dataBuffer != NULL )
dsDataBufferDeallocatePriv( dataBuffer );
if ( localNodeRef != 0 )
dsCloseDirNode( localNodeRef );
if ( dsRef != 0 )
dsCloseDirService( dsRef );
return theRealmStr;
}
void LaunchKerberosAutoConfigTool( void )
{
SInt32 result = eDSNoErr;
mach_port_t mach_init_port = MACH_PORT_NULL;
result = bootstrap_look_up( bootstrap_port, "com.apple.KerberosAutoConfig", &mach_init_port );
if ( result != eDSNoErr )
{
syslog( LOG_ALERT, "Error with bootstrap_look_up for com.apple.KerberosAutoConfig on mach_init port: %s at: %d: Msg = %s\n", __FILE__, __LINE__, mach_error_string( result ) );
}
else
{
sIPCMsg aMsg;
aMsg.fHeader.msgh_bits = MACH_MSGH_BITS( MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND );
aMsg.fHeader.msgh_size = sizeof(sIPCMsg) - sizeof( mach_msg_audit_trailer_t );
aMsg.fHeader.msgh_id = 0;
aMsg.fHeader.msgh_remote_port = mach_init_port;
aMsg.fHeader.msgh_local_port = MACH_PORT_NULL;
aMsg.fMsgType = 0;
aMsg.fCount = 1;
aMsg.fPort = MACH_PORT_NULL;
aMsg.fPID = 0;
aMsg.fMsgID = 0;
aMsg.fOf = 1;
mach_msg((mach_msg_header_t *)&aMsg, MACH_SEND_MSG | MACH_SEND_TIMEOUT, aMsg.fHeader.msgh_size, 0, MACH_PORT_NULL, 1, MACH_PORT_NULL);
mach_port_destroy(mach_task_self(), mach_init_port);
mach_init_port = MACH_PORT_NULL;
}
}
void dsNotifyUpdatedRecord( const char *inModule, const char *inNodeName, const char *inRecType )
{
char tempBuffer[256];
strlcpy( tempBuffer, kDSNotifyGlobalRecordUpdatePrefix, sizeof(tempBuffer) );
strlcat( tempBuffer, inModule, sizeof(tempBuffer) );
strlcat( tempBuffer, ".", sizeof(tempBuffer) );
if ( inNodeName != NULL ) {
strlcat( tempBuffer, inNodeName, sizeof(tempBuffer) );
strlcat( tempBuffer, ".", sizeof(tempBuffer) );
}
strlcat( tempBuffer, inRecType, sizeof(tempBuffer) );
notify_post( tempBuffer );
strlcpy( tempBuffer, kDSNotifyGlobalRecordUpdatePrefix, sizeof(tempBuffer) );
strlcat( tempBuffer, inRecType, sizeof(tempBuffer) );
notify_post( tempBuffer );
}
char *
GenerateRandomComputerPassword( void )
{
const int iPassLength = 20;
char *pCompPassword = (char *) calloc( sizeof(char), iPassLength + 1 );
register char cTemp;
srandomdev();
for ( int iLen = 0; iLen < iPassLength; )
{
cTemp = (char)((random() % (0x7e - 0x21)) + 0x21);
if ( isprint(cTemp) && !isspace(cTemp) )
pCompPassword[iLen++] = cTemp;
}
return pCompPassword;
}