#include "DSTCPEndian.h"
#include <string.h>
#include <errno.h> // system call error numbers
#include <unistd.h> // for select call
#include <stdlib.h> // for calloc()
#include <stdio.h>
#include <ctype.h>
#include "CLog.h"
#define DUMP_BUFFER 0
#if DUMP_BUFFER
char* objectTypes[] =
{
"kResult",
"ktDirRef",
"ktNodeRef",
"ktRecRef",
"ktAttrListRef",
"ktAttrValueListRef",
"ktDataBuff",
"ktDataList",
"ktDirPattMatch",
"kAttrPattMatch",
"kAttrMatch",
"kMatchRecCount",
"kNodeNamePatt",
"ktAccessControlEntry",
"ktAttrEntry",
"ktAttrValueEntry",
"kOpenRecBool",
"kAttrInfoOnly",
"kRecFlags",
"kAttrFlags",
"kRecEntryIndex",
"kAttrInfoIndex",
"kAttrValueIndex",
"kAttrValueID",
"kOutBuffLen",
"kAuthStepDataLen",
"kAuthOnlyBool",
"kDirNodeName",
"kAuthMethod",
"kNodeInfoTypeList",
"kRecNameList",
"kRecTypeList",
"kAttrTypeList",
"kRecTypeBuff",
"kRecNameBuff",
"kAttrType",
"kAttrTypeBuff",
"kAttrValueBuff",
"kNewAttrBuff",
"kFirstAttrBuff",
"unknown",
"kAttrBuff",
"kAuthStepBuff",
"kAuthResponseBuff",
"kAttrTypeRequestList",
"kCustomRequestCode",
"kPluginName",
"kNodeCount",
"kNodeIndex",
"kAttrInfoCount",
"kAttrRecEntryCount",
"ktRecordEntry",
"kAuthStepDataResponse",
"kContextData",
"ktPidRef",
"ktGenericRef",
"kNodeChangeToken",
"ktEffectiveUID",
"ktUID"
};
FILE* gDumpFile = NULL;
void DumpBuf(char* buf, uInt32 len)
{
char acsiiBuf[17];
for (uInt32 i = 0; i < len; i++)
{
if ((i % 16) == 0) ::memset(acsiiBuf, 0, 17);
fprintf(gDumpFile, "%02X ", buf[i]);
if (::isprint(buf[i]))
acsiiBuf[i % 16] = buf[i];
else
acsiiBuf[i % 16] = '.';
if ((i % 16) == 15) fprintf(gDumpFile, " %s\n", acsiiBuf);
}
}
#endif
DSTCPEndian::DSTCPEndian(sComProxyData* fMessage, int direction) : fMessage(fMessage)
{
toBig = (direction == kSwapToBig);
}
void DSTCPEndian::SwapMessage()
{
short i;
sObject* object;
bool isTwoWay = false;
if (fMessage == nil) return;
#if DUMP_BUFFER
uInt32 bufSize = 0;
if (gDumpFile == NULL)
gDumpFile = fopen("/Library/Logs/DirectoryService/PacketDump", "w");
if (toBig)
fprintf(gDumpFile, "\n\n\nBuffer in host order (preSwap)\n");
else
fprintf(gDumpFile, "\n\n\nBuffer in network order (preSwap)\n");
for (i=0; i< 10; i++)
{
object = &fMessage->obj[i];
uInt32 objType = GetLong(&object->type);
uInt32 offset = GetLong(&object->offset);
uInt32 length = GetLong(&object->length);
char* type = "unknown";
if (objType >= 4460 && objType <= 4519)
type = objectTypes[objType - 4460];
if (objType != 0)
{
if (length > 0)
fprintf(gDumpFile, "Object %d, type %s, offset %ld, size %ld\n", i, type, GetLong(&object->offset), GetLong(&object->length));
else
fprintf(gDumpFile, "Object %d, type %s, value %ld\n", i, type, GetLong(&object->count));
}
if (length > 0)
{
uInt32 size = offset + length - sizeof(sComProxyData) + 4;
if (size > bufSize) bufSize = size;
}
}
DumpBuf(fMessage->data, bufSize);
#endif
SwapLong(&fMessage->fDataSize);
SwapLong(&fMessage->fDataLength);
SwapLong(&fMessage->fMsgID);
SwapLong(&fMessage->fPID);
for (i=0; i< 10; i++)
{
object = &fMessage->obj[i];
uInt32 objType = GetLong(&object->type);
if (objType == kAuthMethod)
{
char* method = (char *)fMessage + GetLong(&object->offset);
if ( ::strcmp( method, kDSStdAuth2WayRandom ) == 0 )
isTwoWay = true;
}
}
for (i=0; i< 10; i++)
{
object = &fMessage->obj[i];
if (object->type == 0)
continue;
uInt32 objType = GetAndSwapLong(&object->type);
SwapLong(&object->count);
uInt32 objOffset = GetAndSwapLong(&object->offset);
SwapLong(&object->used);
uInt32 objLength = GetAndSwapLong(&object->length);
SwapObjectData(objType, (char *)fMessage + objOffset, objLength, (!isTwoWay));
}
#if DUMP_BUFFER
if (toBig)
fprintf(gDumpFile, "\n\nBuffer in network order (post Swap)\n");
else
fprintf(gDumpFile, "\n\nBuffer in host order (post Swap)\n");
DumpBuf(fMessage->data, bufSize);
fflush(stdout);
#endif
}
void DSTCPEndian::SwapObjectData(uInt32 type, char* data, uInt32 size, bool swapAuth)
{
switch (type)
{
case ktDataBuff:
{
SwapStandardBuf(data, size);
}
case kAttrMatch:
case kAttrType:
case kAuthResponseBuff:
case kAuthMethod:
case kAttrTypeBuff:
case kAttrValueBuff:
case kFirstAttrBuff:
case kNewAttrBuff:
case kRecNameBuff:
case kRecTypeBuff:
break;
case kAuthStepBuff:
case kAuthStepDataResponse:
{
if (!swapAuth)
{
break;
}
}
case ktDataList:
case kDirNodeName:
case kAttrTypeRequestList:
case kRecTypeList:
case kAttrTypeList:
case kRecNameList:
case kNodeInfoTypeList:
case kNodeNamePatt:
{
uInt32 totalLen = 0;
while (totalLen < size)
{
uInt32 length = GetAndSwapLong(data);
totalLen += length + 4;
data += length + 4;
}
break;
}
case ktAttrEntry:
{
tAttributeEntry* entry = (tAttributeEntry*)data;
SwapLong(&entry->fAttributeValueCount);
SwapLong(&entry->fAttributeDataSize);
SwapLong(&entry->fAttributeValueMaxSize);
SwapLong(&entry->fAttributeSignature.fBufferSize);
SwapLong(&entry->fAttributeSignature.fBufferLength);
break;
}
case ktAttrValueEntry:
{
tAttributeValueEntry* entry = (tAttributeValueEntry*)data;
SwapLong(&entry->fAttributeValueID);
SwapLong(&entry->fAttributeValueData.fBufferSize);
SwapLong(&entry->fAttributeValueData.fBufferLength);
break;
}
case ktRecordEntry:
{
short tempLen;
tRecordEntry* entry = (tRecordEntry*)data;
SwapLong(&entry->fRecordAttributeCount);
SwapLong(&entry->fRecordNameAndType.fBufferSize);
SwapLong(&entry->fRecordNameAndType.fBufferLength);
char* ptr = (char*)&entry->fRecordNameAndType.fBufferData[0];
tempLen = GetAndSwapShort(ptr);
ptr += tempLen + 2;
SwapShort(ptr);
break;
}
default:
if (size != 0)
{
#ifdef DSSERVERTCP
DBGLOG3( kLogTCPEndpoint, "*** DS Error in: %s at: %d: Unexpected pObj of type %d\n", __FILE__, __LINE__, type );
#else
LOG3( kStdErr, "*** DS Error in: %s at: %d: Unexpected pObj\n of type %d", __FILE__, __LINE__, type );
#endif
}
break;
}
}
void DSTCPEndian::SwapStandardBuf(char* data, uInt32 size)
{
if (size < 12)
return;
uInt32 type = GetLong(data);
if ((type == 'StdA') || (type == 'StdB') || (type == 'Gdni'))
{
SwapLong(data);
uInt32 recordCount = GetAndSwapLong(data + 4);
for (uInt32 j = 0; j < recordCount; j++)
{
uInt32 offset = GetAndSwapLong(data + (j * 4) + 8);
if (offset > size) return; SwapRecordEntry(data + offset, type);
}
SwapLong(data + (recordCount * 4) + 8);
}
else if (type == 'npss')
{
SwapLong(data);
uInt32 nodeCount = GetAndSwapLong(data + 4);
for (uInt32 i = 0; i < nodeCount; i++)
{
uInt32 offset = GetAndSwapLong(data + size - (4 * i) - 4);
if (offset > size) return;
char* tempPtr = data + offset;
uInt16 numSegments = GetAndSwapShort(tempPtr);
tempPtr += 2;
for (short j = 0; j < numSegments; j++)
{
uInt16 segmentLen = GetAndSwapShort(tempPtr);
tempPtr += 2 + segmentLen;
if (tempPtr - data > (long)size) return;
}
}
}
}
void DSTCPEndian::SwapRecordEntry(char* data, uInt32 type)
{
uInt32 entryLen = GetAndSwapLong(data);
char* dataEnd = data + entryLen;
data += 4;
uInt16 tempLen = GetAndSwapShort(data);
data += 2 + tempLen;
if (data > dataEnd) return;
tempLen = GetAndSwapShort(data);
data += 2 + tempLen;
if (data > dataEnd) return;
uInt16 attrCount = GetAndSwapShort(data);
data += 2;
for (short i = 0; i < attrCount; i++)
{
uInt32 attrLen;
char* attrEnd = data;
if (type != 'stdB')
{
attrLen = GetAndSwapLong(data);
data += 4;
}
else
{
attrLen = GetAndSwapShort(data);
data += 2;
}
attrEnd += attrLen;
if (attrEnd > dataEnd) return;
tempLen = GetAndSwapShort(data);
data += 2 + tempLen;
if (data > attrEnd) return;
uInt16 attrValCount = GetAndSwapShort(data);
data += 2;
for (short j = 0; j < attrValCount; j++)
{
uInt32 attrValueLen;
if (type != 'stdB')
{
attrValueLen = GetAndSwapLong(data);
data += 4;
}
else
{
attrValueLen = GetAndSwapShort(data);
data += 2;
}
data += attrValueLen;
}
}
}