DSTCPEndian.cpp   [plain text]


/*
 * Copyright (c) 2002 Apple Computer, 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@
 */

/*!
 * @header DSTCPEndian
 * Provides routines to byte swap DSProxy buffers.
 */
 
#ifndef __BIG_ENDIAN__

#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 <syslog.h>
#include <Security/Authorization.h>

#ifdef DSSERVERTCP

#include "CServerPlugin.h"
#include "CLog.h"
#include "CRefTable.h"

#else

#include "CDSRefMap.h"

#endif

#include "CSharedData.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",
	
	"kAttrMatches",
	"kAttrValueList"
};

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 == kDSSwapToBig);
	fIPAddress = 0;
	fPort = 0;
}

void DSTCPEndian::SwapMessage()
{
    short i;
    sObject* object;
    bool isTwoWay = false;
	uInt32 ourMsgID = 0;
    
    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 = DSGetLong(&object->type, toBig);
        uInt32 offset = DSGetLong(&object->offset, toBig);
        uInt32 length = DSGetLong(&object->length, toBig);
        char* type = "unknown";
        if (objType >= kResult && objType <= kAttrValueList)
            type = objectTypes[objType - kResult];
        if (objType != 0)
        {
            if (length > 0)
                    fprintf(gDumpFile, "Object %d, type %s, offset %ld, size %ld\n", i, type, DSGetLong(&object->offset, toBig), DSGetLong(&object->length, toBig));
            else
                    fprintf(gDumpFile, "Object %d, type %s, value %ld\n", i, type, DSGetLong(&object->count, toBig));
        }
        if (length > 0)
        {
            uInt32 size = offset + length - sizeof(sComProxyData) + 4;
            if (size > bufSize) bufSize = size;
        }
    }
    DumpBuf(fMessage->data, bufSize);
#endif
    
	ourMsgID = fMessage->fMsgID; //want this to be consistent below as host order

    DSSwapLong(&fMessage->fDataSize, toBig);
    DSSwapLong(&fMessage->fDataLength, toBig);
    DSSwapLong(&fMessage->fMsgID, toBig);
    DSSwapLong(&fMessage->fPID, toBig); //FW side uses PID BUT the server receiving side uses the TCP port instead
    //DSSwapLong(&fMessage->fIPAddress, toBig); //obtained directly from the endpoint and not present yet in this value
    
	uInt32 aNodeRef = 0;
#ifndef DSSERVERTCP
	uInt32 aNodeRefMap = 0; //used with ktNodeRefMap only for FW
#endif
	//handle CustomCall endian issues - need to determine which plugin is being used
	bool bCustomCall = false;
	uInt32 aCustomRequestNum = 0;
	bool bIsAPICallResponse = false;
	const char* aPluginName = nil;
    // if this is the auth case, we need to do some checks
    for (i=0; i< 10; i++)
    {
        object = &fMessage->obj[i];
        uInt32 objType = DSGetLong(&object->type, toBig);

        // check for two-way random special case before we start swapping stuff
        if (objType == kAuthMethod)
        {
            char* method = (char *)fMessage + DSGetLong(&object->offset, toBig);
            if ( ::strcmp( method, kDSStdAuth2WayRandom ) == 0 )
                isTwoWay = true;
        }

		//check for Custom Call special casing
		if (objType == kCustomRequestCode)
		{
			bCustomCall = true;
			aCustomRequestNum = (uInt32)DSGetLong(&object->count, toBig);
#ifdef DSSERVERTCP
DBGLOG1(kLogTCPEndpoint, "DSSERVERTCP>DSTCPEndian::SwapMessage(): kCustomRequestCode with code %u", aCustomRequestNum );
#else
LOG1(kStdErr, "FW-DSTCPEndian::SwapMessage(): kCustomRequestCode with code %u", aCustomRequestNum );
#endif
		}
		
		if (objType == ktNodeRef)
		{
			//need to determine the nodename for discrimination of duplicate custom call codes - server and FW sends
			aNodeRef = (uInt32)DSGetLong(&object->count, toBig);
		}
#ifndef DSSERVERTCP
		if (objType == ktNodeRefMap)
		{
			//need to determine the nodename for discrimination of duplicate custom call codes - FW only
			aNodeRefMap = (uInt32)DSGetLong(&object->count, toBig);
			//need to keep this since it should come back as well from the server
		}
#endif

		if (objType == kResult)
		{
			bIsAPICallResponse = true;
		}
    } // for (i=0; i< 10; i++)
	
#ifndef DSSERVERTCP
	if (bIsAPICallResponse)
	{
		DSSwapLong(&ourMsgID, toBig);
		if (aCustomRequestNum == 0)
		{
			aCustomRequestNum = CDSRefMap::GetCustomCodeFromMsgIDMap( ourMsgID );
			if (aCustomRequestNum != 0)
			{
				CDSRefMap::RemoveMsgIDToCustomCodeMap( ourMsgID );
				bCustomCall = true;
			}
		}
	}
#endif

	if ( bCustomCall && (aCustomRequestNum != 0) )
	{
#ifdef DSSERVERTCP
		if (aNodeRef != 0)
		{
			CServerPlugin *aPluginPtr = nil;
			sInt32 myResult = CRefTable::VerifyNodeRef( aNodeRef, &aPluginPtr, fPort, fIPAddress );
			if (myResult == eDSNoErr)
			{
				aPluginName = aPluginPtr->GetPluginName();
				if (aPluginName != nil)
				{
				}
			}
		}
#else
		if (aNodeRefMap != 0)
		{
			CDSRefMap::MapMsgIDToServerRef( ourMsgID, aNodeRef );
			CDSRefMap::MapMsgIDToCustomCode( ourMsgID, aCustomRequestNum );
			aPluginName = CDSRefMap::GetPluginName( aNodeRefMap, getpid() ); //FW side this PID should work but on server side we use the IP Port instead
			if (aPluginName != nil)
			{
			}
		}
		else
		{
			if (bIsAPICallResponse)
			{
				uInt32 ourServerRef = 0;
				ourServerRef = CDSRefMap::GetServerRefFromMsgIDMap( ourMsgID );
				CDSRefMap::RemoveMsgIDToServerRefMap( ourMsgID );
				aNodeRefMap = CDSRefMap::GetLocalRefFromServerMap( ourServerRef );
				
				aPluginName = CDSRefMap::GetPluginName( aNodeRefMap, getpid() ); //FW side this PID should work but on server side we use the IP Port instead
				if (aPluginName != nil)
				{
				}
			}
		}
#endif
	}

    // swap objects
    for (i=0; i< 10; i++)
    {
        object = &fMessage->obj[i];

        if (object->type == 0)
            continue;
            
        uInt32 objType = DSGetAndSwapLong(&object->type, toBig);
        DSSwapLong(&object->count, toBig);
        uInt32 objOffset = DSGetAndSwapLong(&object->offset, toBig);
        DSSwapLong(&object->used, toBig);
        uInt32 objLength = DSGetAndSwapLong(&object->length, toBig);
            
        DSSwapObjectData(objType, (char *)fMessage + objOffset, objLength, (!isTwoWay), bCustomCall, aCustomRequestNum, (const char*)aPluginName, bIsAPICallResponse, toBig);
    }
    
#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::AddIPAndPort( uInt32 inIPAddress, uInt32 inPort)
{
	fIPAddress = inIPAddress;
	fPort = inPort;
}


#endif