/*
* Copyright (c) 2007 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#import "PSUtilities.h"
#import "AuthDBFileDefs.h"
// ---------------------------------------------------------------------------
// * pwsf_GetServerListFromConfig
// ---------------------------------------------------------------------------
long pwsf_GetServerListFromConfig( CFMutableArrayRef *outServerList, ReplicaFile *inReplicaData )
{
long status = 0;
CFMutableArrayRef serverArray;
if ( outServerList == NULL || inReplicaData == NULL )
return kAuthFail;
*outServerList = NULL;
serverArray = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
if ( serverArray == NULL )
return kAuthFail;
status = pwsf_GetServerListFromXML( inReplicaData, serverArray );
if ( CFArrayGetCount(serverArray) > 0 )
{
*outServerList = serverArray;
status = 0;
}
else
{
CFRelease( serverArray );
}
return status;
}
// ---------------------------------------------------------------------------
// * pwsf_GetServerListFromXML
// ---------------------------------------------------------------------------
long
pwsf_GetServerListFromXML( ReplicaFile *inReplicaFile, CFMutableArrayRef inOutServerList )
{
CFDictionaryRef serverDict;
CFStringRef serverID;
CFStringRef ldapServerString = NULL;
UInt32 repIndex;
UInt32 repCount;
int ipIndex = 0;
long status = 0;
sPSServerEntry serverEntry;
char ldapServerStr[256] = {0};
if ( inOutServerList == NULL )
return kAuthFail;
bzero( &serverEntry, sizeof(sPSServerEntry) );
ldapServerString = [inReplicaFile currentServerForLDAP];
if ( ldapServerString != NULL )
{
CFStringGetCString( ldapServerString, ldapServerStr, sizeof(ldapServerStr), kCFStringEncodingUTF8 );
CFRelease( ldapServerString );
}
serverID = [inReplicaFile getUniqueID];
if ( serverID != NULL ) {
CFStringGetCString( serverID, serverEntry.id, sizeof(serverEntry.id), kCFStringEncodingUTF8 );
CFRelease( serverID );
}
if ( serverEntry.id[0] == '\0' )
return kAuthFail;
serverDict = [inReplicaFile getParent];
if ( serverDict != NULL )
{
for ( ipIndex = 0, status = 0; status == 0; ipIndex++ )
{
status = GetServerFromDict( serverDict, ipIndex, &serverEntry );
if ( status == 0 )
{
if ( strcmp(serverEntry.ip, ldapServerStr) == 0 )
serverEntry.currentServerForLDAP = YES;
AppendToArrayIfUnique( inOutServerList, &serverEntry );
}
}
}
repCount = [inReplicaFile replicaCount];
for ( repIndex = 0; repIndex < repCount; repIndex++ )
{
serverDict = [inReplicaFile getReplica:repIndex];
if ( serverDict != NULL )
{
for ( ipIndex = 0, status = 0; status == 0; ipIndex++ )
{
status = GetServerFromDict( serverDict, ipIndex, &serverEntry );
if ( status == 0 )
{
if ( strcmp(serverEntry.ip, ldapServerStr) == 0 )
serverEntry.currentServerForLDAP = YES;
AppendToArrayIfUnique( inOutServerList, &serverEntry );
}
}
}
}
status = ( (CFArrayGetCount(inOutServerList) > 0) ? 0 : kAuthFail );
return status;
}
// ---------------------------------------------------------------------------
// * pwsf_ReadSyncDataFromServerWithCASTKey
// Format is:
// Header: 40 bytes fixed size, padded with spaces
// +MORE type byte-count compressed-record-length
//
// Body: RC5 data (binary)
// ---------------------------------------------------------------------------
PWServerError pwsf_ReadSyncDataFromServerWithCASTKey(
sPSContextData *inContext,
unsigned char **dataBuffer,
int *dataTypePtr,
unsigned int *dataSizePtr,
unsigned int *dataLenPtr )
{
PWServerError result = { 0, kConnectionError };
PWServerError connectionErr = { -1, kConnectionError };
char castDescBuffer[kMoreHeaderReserveSize] = {0};
char plainDescBuffer[kMoreHeaderReserveSize] = {0};
unsigned char *buffer = NULL;
unsigned long byteCount = 0;
char *tptr = NULL;
int tryIndex = 0;
*dataBuffer = NULL;
// PEEK the header data //
// we don't know the length yet, so don't wait //
// readFromServerGetData() reserves a byte for a zero-terminator, so add 1 to the length //
// make sure we get the minimum amount of data for a valid response //
while ( byteCount < sizeof("+OK\r\n") - 1 )
{
result = readFromServerGetData( inContext->fd, castDescBuffer, sizeof(castDescBuffer) + 1, &byteCount );
if ( result.err != 0 || byteCount == 0 )
return result;
if ( byteCount < sizeof("+OK\r\n") - 1 )
usleep( 10 );
}
// if the incoming data is a replication record, keep peeking until we get the fixed 40 bytes
for ( tryIndex = 1;
tryIndex < 3 &&
byteCount > sizeof(kPWMoreDataPrefix) - 1 &&
strncmp(castDescBuffer, kPWMoreDataPrefix, sizeof(kPWMoreDataPrefix) - 1) == 0 &&
byteCount < kMoreHeaderReserveSize;
tryIndex++ )
{
result = readFromServerGetData( inContext->fd, castDescBuffer, sizeof(castDescBuffer) + 1, &byteCount );
if ( result.err != 0 || byteCount == 0 )
return result;
if ( byteCount < kMoreHeaderReserveSize )
usleep( 10 );
}
// protocol enforcement
if ( byteCount > sizeof(kPWMoreDataPrefix) - 1 &&
strncmp(castDescBuffer, kPWMoreDataPrefix, sizeof(kPWMoreDataPrefix) - 1) == 0 &&
byteCount < kMoreHeaderReserveSize )
{
return connectionErr;
}
// Consume the bytes off the TCP stack //
recvfrom( inContext->fd, plainDescBuffer, byteCount, MSG_WAITALL, NULL, NULL );
// if (byteCount if ( inContext->castKeySet && !inContext->isUNIXDomainSocket )
{
CAST_cbc_encrypt(
(unsigned char *)castDescBuffer,
(unsigned char *)plainDescBuffer,
byteCount,
&inContext->castKey,
inContext->castReceiveIV,
CAST_DECRYPT );
}
// If this is a replication record, read the rest //
if ( byteCount > sizeof(kPWMoreDataPrefix) - 1 &&
strncmp(plainDescBuffer, kPWMoreDataPrefix, sizeof(kPWMoreDataPrefix) - 1) == 0 )
{
// protocol enforcement
if ( byteCount != kMoreHeaderReserveSize )
return connectionErr;
// parse the header
sscanf( plainDescBuffer + 6, " if ( *dataTypePtr < kDBTypeLastSyncTime || *dataTypePtr > kDBTypeKerberosPrincipal || *dataLenPtr > *dataSizePtr )
return connectionErr;
// make a read and decrypt buffer
buffer = (unsigned char *) malloc( (*dataSizePtr) * 2 );
if ( buffer == NULL ) {
connectionErr.type = kGeneralError;
return connectionErr;
}
// read the data blob
if ( inContext->castKeySet && !inContext->isUNIXDomainSocket )
{
byteCount = recvfrom( inContext->fd, buffer + *dataSizePtr, *dataSizePtr, MSG_WAITALL, NULL, NULL );
CAST_cbc_encrypt( buffer + *dataSizePtr, buffer, byteCount, &inContext->castKey, inContext->castReceiveIV, CAST_DECRYPT );
}
else
{
byteCount = recvfrom( inContext->fd, buffer, *dataSizePtr, MSG_WAITALL, NULL, NULL );
}
*dataBuffer = buffer;
}
else
{
tptr = strstr( plainDescBuffer, "\r\n" );
if ( tptr != NULL ) {
*tptr = '\0';
result = readFromServerGetErrorCode( plainDescBuffer );
}
}
return result;
}