1110 lines
28 KiB
C++
1110 lines
28 KiB
C++
//----------------------------------------------------------------------------
|
|
//
|
|
// Copyright (C) 2006 Intel Corporation
|
|
//
|
|
// File: SetupFileReaderWriter.cpp
|
|
//
|
|
// Contents: Demonstrates how to read and write a configuration setup file.
|
|
//
|
|
// Notes: This file contains a number of functions that demonstrate how
|
|
// to read and write a configuration setup file.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include <windows.h>
|
|
|
|
#include "SetupFileReaderWriter.h"
|
|
#include "ConfigFile.h"
|
|
|
|
static const char* G_S_DEFAULT_MEBX_PWD = "admin";
|
|
static const unsigned short G_S_DEFAULT_MEBX_PWD_LENGTH = 5;
|
|
|
|
////////////////////////////
|
|
// DataRecordEntry functions
|
|
////////////////////////////
|
|
DataRecordEntry::DataRecordEntry()
|
|
{
|
|
_moduleId = 0;
|
|
_variableId = 0;
|
|
_variableLength = 0;
|
|
_variableValue = NULL;
|
|
}
|
|
|
|
DataRecordEntry::DataRecordEntry(const unsigned short moduleId,
|
|
const unsigned short variableId,
|
|
const unsigned short variableLength,
|
|
const unsigned char* variableValue)
|
|
{
|
|
_variableValue = NULL;
|
|
SetModuleId(moduleId);
|
|
SetVariableId(variableId);
|
|
SetVariableValue(variableLength, variableValue);
|
|
}
|
|
|
|
DataRecordEntry::DataRecordEntry(const DataRecordEntry& entry)
|
|
{
|
|
_variableValue = NULL;
|
|
SetModuleId(entry._moduleId);
|
|
SetVariableId(entry._variableId);
|
|
SetVariableValue(entry._variableLength, entry._variableValue);
|
|
}
|
|
|
|
DataRecordEntry& DataRecordEntry::operator=(const DataRecordEntry& entry)
|
|
{
|
|
if (this == &entry)
|
|
return *this;
|
|
_variableValue = NULL;
|
|
SetModuleId(entry._moduleId);
|
|
SetVariableId(entry._variableId);
|
|
SetVariableValue(entry._variableLength, entry._variableValue);
|
|
return *this;
|
|
}
|
|
|
|
DataRecordEntry::~DataRecordEntry()
|
|
{
|
|
if(_variableValue)
|
|
{
|
|
delete _variableValue;
|
|
_variableValue = NULL;
|
|
}
|
|
}
|
|
|
|
unsigned short DataRecordEntry::GetModuleId() const
|
|
{
|
|
return _moduleId;
|
|
}
|
|
|
|
unsigned short DataRecordEntry::GetVariableId() const
|
|
{
|
|
return _variableId;
|
|
}
|
|
|
|
unsigned short DataRecordEntry::GetVariableLength() const
|
|
{
|
|
return _variableLength;
|
|
}
|
|
|
|
unsigned short DataRecordEntry::GetVariableValue(const unsigned short bufferLen,
|
|
unsigned char* buffer) const
|
|
{
|
|
if(_variableValue == NULL ||
|
|
buffer == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
if (memcpy_s(buffer, min(_variableLength, bufferLen), _variableValue, min(_variableLength, bufferLen)))
|
|
{
|
|
printf("Error: Can't Copy Memory");
|
|
return 0;
|
|
}
|
|
|
|
return min(_variableLength, bufferLen);
|
|
}
|
|
|
|
void DataRecordEntry::SetModuleId(const unsigned short moduleId)
|
|
{
|
|
_moduleId = moduleId;
|
|
}
|
|
|
|
void DataRecordEntry::SetVariableId(const unsigned short variableId)
|
|
{
|
|
_variableId = variableId;
|
|
}
|
|
|
|
void DataRecordEntry::SetVariableValue(const unsigned short bufferLen,
|
|
const unsigned char* buffer)
|
|
{
|
|
if(_variableValue)
|
|
{
|
|
delete _variableValue;
|
|
_variableValue = NULL;
|
|
}
|
|
_variableLength = bufferLen;
|
|
_variableValue = new unsigned char[bufferLen];
|
|
if(buffer)
|
|
{
|
|
if (memcpy_s(_variableValue, _variableLength, buffer, bufferLen))
|
|
{
|
|
printf("Error: Can't Copy Memory");
|
|
}
|
|
}
|
|
}
|
|
|
|
///////////////////////
|
|
// DataRecord functions
|
|
///////////////////////
|
|
DataRecord::DataRecord(const bool isValid, const bool isScrambled)
|
|
:_recordEntries(),
|
|
_isValid(isValid),
|
|
_isScrambled(isScrambled)
|
|
{
|
|
_recordEntries = new vector<DataRecordEntry>();
|
|
}
|
|
|
|
DataRecord::DataRecord(const DataRecord& record)
|
|
{
|
|
_recordEntries = NULL;
|
|
CopyRecord(record);
|
|
}
|
|
|
|
DataRecord& DataRecord::operator=(const DataRecord& record)
|
|
{
|
|
if (this == &record)
|
|
return *this;
|
|
_recordEntries = NULL;
|
|
CopyRecord(record);
|
|
return *this;
|
|
}
|
|
|
|
DataRecord::~DataRecord()
|
|
{
|
|
if(_recordEntries)
|
|
{
|
|
delete _recordEntries;
|
|
_recordEntries = NULL;
|
|
}
|
|
}
|
|
|
|
void DataRecord::AddRecordEntry(const unsigned short moduleId,
|
|
const unsigned short variableId,
|
|
const unsigned short variableLength,
|
|
const unsigned char* variableValue)
|
|
{
|
|
DataRecordEntry entry(moduleId, variableId,
|
|
variableLength, variableValue);
|
|
_recordEntries->push_back(entry);
|
|
}
|
|
|
|
bool DataRecord::GetIsValid() const
|
|
{
|
|
return _isValid;
|
|
}
|
|
|
|
bool DataRecord::GetIsScrambled() const
|
|
{
|
|
return _isScrambled;
|
|
}
|
|
|
|
|
|
vector<DataRecordEntry> DataRecord::GetRecordEntries() const
|
|
{
|
|
return *_recordEntries;
|
|
}
|
|
|
|
void DataRecord::SetValid(const bool isValid)
|
|
{
|
|
_isValid = isValid;
|
|
}
|
|
|
|
void DataRecord::SetScrambled(const bool isScrambled)
|
|
{
|
|
_isScrambled = isScrambled;
|
|
}
|
|
|
|
void DataRecord::CopyRecord(const DataRecord& record)
|
|
{
|
|
if(_recordEntries)
|
|
{
|
|
delete _recordEntries;
|
|
_recordEntries = NULL;
|
|
}
|
|
|
|
SetValid(record._isValid);
|
|
|
|
SetScrambled(record._isScrambled);
|
|
|
|
if(record._recordEntries)
|
|
{
|
|
_recordEntries = new vector<DataRecordEntry>(*(record._recordEntries));
|
|
}
|
|
else
|
|
{
|
|
_recordEntries = new vector<DataRecordEntry>();
|
|
}
|
|
}
|
|
|
|
|
|
bool DataRecord::FindEntry(const unsigned short moduleId,
|
|
const unsigned short variableId,
|
|
unsigned short* variableLength,
|
|
const unsigned short bufferLength,
|
|
unsigned char* buffer) const
|
|
{
|
|
vector<DataRecordEntry>::iterator it;
|
|
for(it = _recordEntries->begin(); it != _recordEntries->end(); it++)
|
|
{
|
|
if(it->GetModuleId() == moduleId &&
|
|
it->GetVariableId() == variableId)
|
|
{
|
|
if(variableLength)
|
|
{
|
|
*variableLength = it->GetVariableLength();
|
|
}
|
|
if(buffer)
|
|
{
|
|
it->GetVariableValue(bufferLength, buffer);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
///////////////////
|
|
// Global Functions
|
|
///////////////////
|
|
// Validate a UUID
|
|
bool ValidateUuid(const unsigned char* uuid1, const unsigned char* uuid2)
|
|
{
|
|
if(memcmp(uuid1, uuid2, GUID_SIZE) != 0)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// set a DATA_RECORD_ENTRY_T from a DataRecord
|
|
void SetEntry(DATA_RECORD_ENTRY_T* entry, const DataRecordEntry& recordEntry)
|
|
{
|
|
entry->ModuleIdentifier = recordEntry.GetModuleId();
|
|
entry->VariableIdentifier = recordEntry.GetVariableId();
|
|
entry->VariableLength = recordEntry.GetVariableLength();
|
|
recordEntry.GetVariableValue(recordEntry.GetVariableLength(), &entry->VariableValue);
|
|
}
|
|
|
|
// Parse the SetupFile header
|
|
int ParseFileHeader(const unsigned int bufferLength,
|
|
const unsigned char* buffer,
|
|
SetupFileInfo* fileInfo,
|
|
unsigned int* moduleListSize,
|
|
set<unsigned short>* moduleList)
|
|
{
|
|
if(buffer == NULL)
|
|
{
|
|
return CONFIG_INVALID_BUFFER;
|
|
}
|
|
|
|
SETUP_HEADER_T* fileHeader;
|
|
fileHeader = (SETUP_HEADER_T*)buffer;
|
|
|
|
unsigned char setupFileGuid[GUID_SIZE] = SETUP_GUID;
|
|
unsigned char setupFileGuid2[GUID_SIZE] = SETUP_GUID_2;
|
|
unsigned char setupFileGuid3[GUID_SIZE] = SETUP_GUID_3;
|
|
unsigned char setupFileGuid4[GUID_SIZE] = SETUP_GUID_4;
|
|
|
|
const unsigned char* strSetupFileGuid = NULL;
|
|
switch (fileHeader->MajorVersion)
|
|
{
|
|
case SETUP_FILE_VERSION_1:
|
|
strSetupFileGuid = setupFileGuid;
|
|
break;
|
|
case SETUP_FILE_VERSION_2:
|
|
strSetupFileGuid = setupFileGuid2;
|
|
break;
|
|
case SETUP_FILE_VERSION_3:
|
|
strSetupFileGuid = setupFileGuid3;
|
|
break;
|
|
case SETUP_FILE_VERSION_4:
|
|
strSetupFileGuid = setupFileGuid4;
|
|
break;
|
|
default:
|
|
return CONFIG_VERSION_UNSUPPORTED;
|
|
}
|
|
|
|
if(!ValidateUuid(
|
|
strSetupFileGuid,
|
|
(unsigned char*)&(fileHeader->FileTypeUuid)))
|
|
{
|
|
return CONFIG_INVALID_UUID;
|
|
}
|
|
|
|
if(fileHeader->MajorVersion > MAX_MAJOR_VERSION)
|
|
{
|
|
return CONFIG_VERSION_UNSUPPORTED;
|
|
}
|
|
|
|
if(fileHeader->RecordNumber != 0)
|
|
{
|
|
return CONFIG_INVALID_RECORD_NUMBER;
|
|
}
|
|
|
|
unsigned int length = CHUNK_SIZE * (fileHeader->RecordChunkCount +
|
|
(fileHeader->DataRecordCount * fileHeader->RecordChunkCount));
|
|
|
|
if(length > bufferLength)
|
|
{
|
|
return CONFIG_INVALID_BUFFER_LENGTH;
|
|
}
|
|
|
|
if(fileHeader->RecordHeaderByteCount < sizeof(SETUP_HEADER_T) ||
|
|
fileHeader->RecordHeaderByteCount >
|
|
CHUNK_SIZE * fileHeader->RecordChunkCount)
|
|
{
|
|
return CONFIG_INVALID_RECORD_HEADER_BYTE_COUNT;
|
|
}
|
|
|
|
const unsigned short* TMP = (const unsigned short*)&(fileHeader->ModuleList);
|
|
unsigned int counter = 0;
|
|
unsigned int bytesInHeader = sizeof(SETUP_HEADER_T) - 1;
|
|
while(TMP[counter] != 0)
|
|
{
|
|
counter ++;
|
|
bytesInHeader += 2;
|
|
if(bytesInHeader > fileHeader->RecordHeaderByteCount)
|
|
{
|
|
return CONFIG_INVALID_MODULE_LIST;
|
|
}
|
|
}
|
|
// fill values
|
|
if(fileInfo)
|
|
{
|
|
fileInfo->headerChunkCount = fileHeader->RecordChunkCount;
|
|
fileInfo->recordCount = fileHeader->DataRecordCount;
|
|
fileInfo->recordsConsumed = fileHeader->DataRecordsConsumed;
|
|
fileInfo->dataRecordChunkCount = fileHeader->DataRecordChunkCount;
|
|
fileInfo->majorVersion = fileHeader->MajorVersion;
|
|
fileInfo->minorVersion = fileHeader->MinorVersion;
|
|
fileInfo->consumeRecords = (fileHeader->FileFlags.DontConsumeRecords == 0);
|
|
}
|
|
|
|
if(moduleList)
|
|
{
|
|
for(unsigned int i = 0; i < counter; i++)
|
|
{
|
|
moduleList->insert(TMP[i]);
|
|
}
|
|
}
|
|
if(moduleListSize)
|
|
{
|
|
*moduleListSize = counter;
|
|
}
|
|
return CONFIG_SUCCESS;
|
|
}
|
|
|
|
int WriteFileHeader(unsigned char* buffer,
|
|
const SetupFileInfo fileInfo,
|
|
const set<unsigned short>& moduleList)
|
|
{
|
|
if(buffer == NULL)
|
|
{
|
|
return CONFIG_INVALID_BUFFER;
|
|
}
|
|
unsigned short numLegalModules;
|
|
set<unsigned short>::const_iterator it = moduleList.find(0);
|
|
if(it == moduleList.end())
|
|
{
|
|
numLegalModules = (unsigned short)moduleList.size();
|
|
}
|
|
else
|
|
{
|
|
numLegalModules = (unsigned short)moduleList.size() - 1;
|
|
}
|
|
|
|
unsigned short byteCount = sizeof(SETUP_HEADER_T) + numLegalModules*2;
|
|
|
|
if(byteCount > fileInfo.headerChunkCount*CHUNK_SIZE)
|
|
{
|
|
return CONFIG_INVALID_HEADER_CHUNK_COUNT;
|
|
}
|
|
|
|
memset(buffer, 0, fileInfo.headerChunkCount*CHUNK_SIZE);
|
|
|
|
SETUP_HEADER_T* header = (SETUP_HEADER_T*)buffer;
|
|
|
|
unsigned char setupFileGuid[GUID_SIZE] = SETUP_GUID;
|
|
unsigned char setupFileGuid2[GUID_SIZE] = SETUP_GUID_2;
|
|
unsigned char setupFileGuid3[GUID_SIZE] = SETUP_GUID_3;
|
|
unsigned char setupFileGuid4[GUID_SIZE] = SETUP_GUID_4;
|
|
|
|
|
|
switch (fileInfo.majorVersion)
|
|
{
|
|
case SETUP_FILE_VERSION_1:
|
|
if (memcpy_s(&(header->FileTypeUuid), ARRAYSIZE(header->FileTypeUuid), setupFileGuid, ARRAYSIZE(setupFileGuid)))
|
|
{
|
|
return CONFIG_INVALID_BUFFER;
|
|
}
|
|
break;
|
|
case SETUP_FILE_VERSION_2:
|
|
if (memcpy_s(&(header->FileTypeUuid), ARRAYSIZE(header->FileTypeUuid), setupFileGuid2, ARRAYSIZE(setupFileGuid2)))
|
|
{
|
|
return CONFIG_INVALID_BUFFER;
|
|
}
|
|
break;
|
|
case SETUP_FILE_VERSION_3:
|
|
if (memcpy_s(&(header->FileTypeUuid), ARRAYSIZE(header->FileTypeUuid), setupFileGuid3, ARRAYSIZE(setupFileGuid3)))
|
|
{
|
|
return CONFIG_INVALID_BUFFER;
|
|
}
|
|
break;
|
|
case SETUP_FILE_VERSION_4:
|
|
if (memcpy_s(&(header->FileTypeUuid), ARRAYSIZE(header->FileTypeUuid), setupFileGuid4, ARRAYSIZE(setupFileGuid4)))
|
|
{
|
|
return CONFIG_INVALID_BUFFER;
|
|
}
|
|
break;
|
|
default:
|
|
return CONFIG_VERSION_UNSUPPORTED;
|
|
}
|
|
|
|
bool singleRecord =
|
|
((fileInfo.majorVersion >= SETUP_FILE_VERSION_2) &&
|
|
fileInfo.consumeRecords == false);
|
|
|
|
header->RecordChunkCount = fileInfo.headerChunkCount;
|
|
header->RecordHeaderByteCount = byteCount;
|
|
header->MajorVersion = fileInfo.majorVersion;
|
|
header->MinorVersion = fileInfo.minorVersion;
|
|
header->RecordNumber = 0;
|
|
header->DataRecordCount = singleRecord ? 1 : fileInfo.recordCount;
|
|
header->DataRecordsConsumed = singleRecord ? 0 : fileInfo.recordsConsumed;
|
|
header->DataRecordChunkCount = fileInfo.dataRecordChunkCount;
|
|
header->FileFlags.DontConsumeRecords = singleRecord ? 1 : 0;
|
|
|
|
unsigned short* tmp = &header->ModuleList;
|
|
it = moduleList.begin();
|
|
while(it != moduleList.end())
|
|
{
|
|
if((*it) != 0)
|
|
{
|
|
*tmp = *it;
|
|
tmp++;
|
|
}
|
|
it++;
|
|
}
|
|
*tmp = 0;
|
|
return CONFIG_SUCCESS;
|
|
}
|
|
|
|
// retrieve a Data Record
|
|
int GetDataRecord(const unsigned short numChunks,
|
|
const unsigned char* buffer,
|
|
const unsigned char majorVersion,
|
|
const unsigned char minorVersion,
|
|
set<unsigned short>* legalModules,
|
|
DataRecord* record)
|
|
{
|
|
if(buffer == NULL)
|
|
{
|
|
return CONFIG_INVALID_BUFFER;
|
|
}
|
|
|
|
DATA_RECORD_HEADER_T* recordHeader;
|
|
DATA_RECORD_ENTRY_T* recordEntry;
|
|
|
|
recordHeader = (DATA_RECORD_HEADER_T*)buffer;
|
|
|
|
if(recordHeader->RecordChunkCount != numChunks)
|
|
{
|
|
return CONFIG_INVALID_RECORD_CHUNK_COUNT;
|
|
}
|
|
|
|
unsigned int base = recordHeader->RecordHeaderByteCount;
|
|
if(base > (unsigned int)(numChunks * CHUNK_SIZE))
|
|
{
|
|
return CONFIG_INVALID_RECORD_HEADER_BYTE_COUNT;
|
|
}
|
|
|
|
bool valid = recordHeader->RecordFlags.Valid;
|
|
static bool scrambled = recordHeader->RecordFlags.Scrambled;
|
|
|
|
if(!valid)
|
|
{
|
|
return CONFIG_INVALID_RECORD;
|
|
}
|
|
|
|
if(recordHeader->RecordTypeIdentifier != RECORD_IDENTIFIER_DATA_RECORD)
|
|
{
|
|
return CONFIG_RECORD_TYPE_INVALID;
|
|
}
|
|
|
|
if (scrambled != recordHeader->RecordFlags.Scrambled)
|
|
{
|
|
return CONFIG_INVALID_SCRAMBLED_STATE;
|
|
}
|
|
|
|
DataRecord dr(valid, scrambled);
|
|
unsigned int entryDwordLength;
|
|
|
|
bool first = true;
|
|
|
|
// in SETUP_FILE_VERSION_2 default "admin" must be followed by
|
|
// a new MEBx password
|
|
bool findNewMebxPwd = false;
|
|
|
|
// in SETUP_FILE_VERSION_2
|
|
// ME_VARIABLE_IDENTIFIER_MANAGEABILITY_FEATURE_SELECTION
|
|
// may not appear after any CM settings
|
|
bool cmVarFound = false;
|
|
|
|
// in SETUP_FILE_VERSION_2
|
|
// CM_VARIABLE_IDENTIFIER_USER_DEFINED_CERT_ADD must be preceded
|
|
// by setting CM_VARIABLE_IDENTIFIER_USER_DEFINED_CERTS_CONFIG to
|
|
//
|
|
|
|
if (scrambled)
|
|
{
|
|
DescrambleRecordData((unsigned char *)buffer + base, recordHeader->RecordChunkCount * CHUNK_SIZE - base);
|
|
}
|
|
|
|
while(valid) // if valid is false - do not search for entries
|
|
{
|
|
recordEntry = (DATA_RECORD_ENTRY_T*)(buffer + base);
|
|
if(first)
|
|
{
|
|
// make sure first entry is current MEBx password
|
|
if(recordEntry->ModuleIdentifier != MODULE_IDENTIFIER_ME_KERNEL ||
|
|
recordEntry->VariableIdentifier != ME_VARIABLE_IDENTIFIER_CURRENT_MEBX_PWD)
|
|
{
|
|
return CONFIG_MISSING_CURRENT_MEBX_PWD_ENTRY;
|
|
}
|
|
first = false;
|
|
if(recordEntry->VariableLength == G_S_DEFAULT_MEBX_PWD_LENGTH
|
|
&& memcmp(&(recordEntry->VariableValue), G_S_DEFAULT_MEBX_PWD, min(G_S_DEFAULT_MEBX_PWD_LENGTH, sizeof(recordEntry->VariableValue))) == 0)
|
|
{// default password found
|
|
findNewMebxPwd = true;
|
|
}
|
|
}
|
|
|
|
if(recordEntry->ModuleIdentifier == 0 &&
|
|
recordEntry->VariableIdentifier == 0 &&
|
|
recordEntry->VariableLength == 0 &&
|
|
recordEntry->Reserved == 0)
|
|
{
|
|
// NULL Entry Terminator
|
|
break;
|
|
}
|
|
|
|
if(recordEntry->ModuleIdentifier == MODULE_IDENTIFIER_ME_KERNEL &&
|
|
recordEntry->VariableIdentifier == ME_VARIABLE_IDENTIFIER_NEW_MEBX_PWD)
|
|
{// new MEBx pwd found
|
|
findNewMebxPwd = false;
|
|
}
|
|
|
|
if(recordEntry->ModuleIdentifier ==
|
|
MODULE_IDENTIFIER_ME_KERNEL
|
|
&& recordEntry->VariableIdentifier ==
|
|
ME_VARIABLE_IDENTIFIER_MANAGEABILITY_FEATURE_SELECTION
|
|
&& majorVersion >= SETUP_FILE_VERSION_2)
|
|
{
|
|
if(cmVarFound)
|
|
{
|
|
return CONFIG_INVALID_MANAGEABILITY_FEATURE_SELECTION;
|
|
}
|
|
}
|
|
|
|
if(recordEntry->ModuleIdentifier == MODULE_IDENTIFIER_AMT_CM)
|
|
{
|
|
cmVarFound = true;
|
|
}
|
|
|
|
//if(recordEntry->ModuleIdentifier == MODULE_IDENTIFIER_AMT_CM
|
|
// && recordEntry->VariableIdentifier ==
|
|
// CM_VARIABLE_IDENTIFIER_USER_DEFINED_CERTS_CONFIG
|
|
// && recordEntry->VariableValue == CM_VARIABLE_IDENTIFIER_USER_DEFINED_CERTS_CONFIG_DELETE)
|
|
// {
|
|
// userDefinedCertsDeleted = true;
|
|
//}
|
|
|
|
//if(recordEntry->ModuleIdentifier == MODULE_IDENTIFIER_AMT_CM
|
|
// && recordEntry->VariableIdentifier ==
|
|
// CM_VARIABLE_IDENTIFIER_USER_DEFINED_CERT_ADD
|
|
// && majorVersion >= SETUP_FILE_VERSION_2)
|
|
// {
|
|
// if(!userDefinedCertsDeleted)
|
|
// {
|
|
// return CONFIG_INVALID_CERT_SETTINGS;
|
|
// }
|
|
//}
|
|
|
|
if(legalModules)
|
|
{// validate moduleId
|
|
if(recordEntry->ModuleIdentifier != 0)
|
|
{
|
|
set<unsigned short>::iterator it = legalModules->find(recordEntry->ModuleIdentifier);
|
|
if(it == legalModules->end())
|
|
{
|
|
return CONFIG_INVALID_MODULE_ID;
|
|
}
|
|
}
|
|
// else - filler value
|
|
}
|
|
|
|
dr.AddRecordEntry(recordEntry->ModuleIdentifier,
|
|
recordEntry->VariableIdentifier,
|
|
recordEntry->VariableLength,
|
|
&(recordEntry->VariableValue));
|
|
entryDwordLength = 2 + (recordEntry->VariableLength + 3)/4;
|
|
base += 4*entryDwordLength;
|
|
if(base > (unsigned int)CHUNK_SIZE * numChunks)
|
|
{
|
|
return CONFIG_INVALID_ENTRY_LIST;
|
|
}
|
|
}
|
|
|
|
if(majorVersion >= SETUP_FILE_VERSION_2 && findNewMebxPwd)
|
|
{
|
|
return CONFIG_MISSING_NEW_MEBX_PWD_ENTRY;
|
|
}
|
|
if(record)
|
|
{
|
|
record->CopyRecord(dr);
|
|
}
|
|
return CONFIG_SUCCESS;
|
|
}
|
|
|
|
int WriteDataRecord(const unsigned short numChunks,
|
|
unsigned char* buffer,
|
|
const unsigned char majorVersion,
|
|
const unsigned char minorVersion,
|
|
const unsigned int recordNumber,
|
|
const DataRecord& record,
|
|
set<unsigned short>* modulesUsed)
|
|
{
|
|
if(buffer == NULL)
|
|
{
|
|
return CONFIG_INVALID_BUFFER;
|
|
}
|
|
|
|
unsigned int requiredDwords = (sizeof(DATA_RECORD_HEADER_T) + 3)/4;
|
|
|
|
bool currentMEBxPwdFound = false;
|
|
bool isDefaultMEBxPwd = false;
|
|
bool newMEBxPwdFound = false;
|
|
bool manFeatureFound = false;
|
|
|
|
bool pkiDnsSuffixFound = false;
|
|
bool configServerFqdnFound = false;
|
|
bool provisioningServerAddressFound = false;
|
|
bool meProvisioningHaltActivateFound = false;
|
|
|
|
int currPwdIndex = -1;
|
|
int newPwdIndex = -1;
|
|
int manSelectionIndex = -1;
|
|
|
|
int meProvisioningHaltActivateIndex = -1;
|
|
|
|
vector<DataRecordEntry> entries = record.GetRecordEntries();
|
|
unsigned int numEntries = (unsigned int)entries.size();
|
|
|
|
for(unsigned int i = 0; i < numEntries; i++)
|
|
{
|
|
if(entries[i].GetModuleId() == MODULE_IDENTIFIER_ME_KERNEL &&
|
|
entries[i].GetVariableId() == ME_VARIABLE_IDENTIFIER_CURRENT_MEBX_PWD)
|
|
{
|
|
currPwdIndex = i;
|
|
currentMEBxPwdFound = true;
|
|
if(entries[i].GetVariableLength() == G_S_DEFAULT_MEBX_PWD_LENGTH)
|
|
{
|
|
unsigned char tmp[G_S_DEFAULT_MEBX_PWD_LENGTH + 1];
|
|
entries[i].GetVariableValue(G_S_DEFAULT_MEBX_PWD_LENGTH + 1, &(tmp[0]));
|
|
if(memcmp(tmp, G_S_DEFAULT_MEBX_PWD, G_S_DEFAULT_MEBX_PWD_LENGTH) == 0)
|
|
{
|
|
isDefaultMEBxPwd = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(entries[i].GetModuleId() == MODULE_IDENTIFIER_ME_KERNEL &&
|
|
entries[i].GetVariableId() == ME_VARIABLE_IDENTIFIER_NEW_MEBX_PWD)
|
|
{
|
|
newPwdIndex = i;
|
|
newMEBxPwdFound = true;
|
|
}
|
|
|
|
if(entries[i].GetModuleId() == MODULE_IDENTIFIER_ME_KERNEL &&
|
|
entries[i].GetVariableId() == ME_VARIABLE_IDENTIFIER_MANAGEABILITY_FEATURE_SELECTION)
|
|
{
|
|
manSelectionIndex = i;
|
|
manFeatureFound = true;
|
|
}
|
|
|
|
if(entries[i].GetModuleId() == MODULE_IDENTIFIER_AMT_CM &&
|
|
entries[i].GetVariableId() == CM_VARIABLE_IDENTIFIER_PKI_DNS_SUFFIX)
|
|
{
|
|
pkiDnsSuffixFound = true;
|
|
}
|
|
|
|
if(entries[i].GetModuleId() == MODULE_IDENTIFIER_AMT_CM &&
|
|
entries[i].GetVariableId() == CM_VARIABLE_IDENTIFIER_CONFIG_SERVER_FQDN)
|
|
{
|
|
configServerFqdnFound = true;
|
|
}
|
|
|
|
if(entries[i].GetModuleId() == MODULE_IDENTIFIER_AMT_CM &&
|
|
entries[i].GetVariableId() == CM_VARIABLE_IDENTIFIER_PSADDR)
|
|
{
|
|
provisioningServerAddressFound = true;
|
|
}
|
|
|
|
if(entries[i].GetModuleId() == MODULE_IDENTIFIER_AMT_CM &&
|
|
entries[i].GetVariableId() == CM_VARIABLE_IDENTIFIER_ME_PROVISION_HALT_ACTIVE)
|
|
{
|
|
meProvisioningHaltActivateIndex = i;
|
|
meProvisioningHaltActivateFound = true;
|
|
}
|
|
requiredDwords += (2 + (entries[i].GetVariableLength() + 3)/4);
|
|
}
|
|
requiredDwords += 2; // for NULL terminating entry
|
|
|
|
if(!currentMEBxPwdFound)
|
|
{
|
|
return CONFIG_MISSING_CURRENT_MEBX_PWD_ENTRY;
|
|
}
|
|
|
|
if(majorVersion >= SETUP_FILE_VERSION_2 && isDefaultMEBxPwd && !newMEBxPwdFound)
|
|
{
|
|
return CONFIG_MISSING_NEW_MEBX_PWD_ENTRY;
|
|
}
|
|
|
|
if(4*requiredDwords > (unsigned int)numChunks*CHUNK_SIZE)
|
|
{
|
|
return CONFIG_INVALID_RECORD_CHUNK_COUNT;
|
|
}
|
|
|
|
memset(buffer, 0, numChunks*CHUNK_SIZE);
|
|
|
|
DATA_RECORD_HEADER_T* header;
|
|
DATA_RECORD_ENTRY_T* entry;
|
|
|
|
bool scrambled = record.GetIsScrambled();
|
|
|
|
header = (DATA_RECORD_HEADER_T*)buffer;
|
|
header->RecordTypeIdentifier = RECORD_IDENTIFIER_DATA_RECORD;
|
|
header->RecordFlags.Valid = (record.GetIsValid()) ? 1 : 0;
|
|
header->RecordFlags.Scrambled = scrambled ? 1 : 0;
|
|
header->RecordChunkCount = numChunks;
|
|
unsigned short headerDwords = ((sizeof(DATA_RECORD_HEADER_T) + 3)/4) * 4;
|
|
header->RecordHeaderByteCount = headerDwords;
|
|
header->RecordNumber = recordNumber;
|
|
unsigned int base = header->RecordHeaderByteCount;
|
|
unsigned int entryDwordLength;
|
|
|
|
// first insert CurrentMEBx Pwd
|
|
entry = (DATA_RECORD_ENTRY_T*)(buffer + base);
|
|
SetEntry(entry, entries[currPwdIndex]);
|
|
if(modulesUsed)
|
|
{
|
|
modulesUsed->insert(entries[currPwdIndex].GetModuleId());
|
|
}
|
|
entryDwordLength = 2 + (entry->VariableLength + 3)/4;
|
|
base += 4*entryDwordLength;
|
|
|
|
// next insert newMebx, if found
|
|
if(newMEBxPwdFound)
|
|
{
|
|
entry = (DATA_RECORD_ENTRY_T*)(buffer + base);
|
|
SetEntry(entry, entries[newPwdIndex]);
|
|
entryDwordLength = 2 + (entry->VariableLength + 3)/4;
|
|
base += 4*entryDwordLength;
|
|
}
|
|
// next insert manageability selection, if found
|
|
if(manFeatureFound)
|
|
{
|
|
entry = (DATA_RECORD_ENTRY_T*)(buffer + base);
|
|
SetEntry(entry, entries[manSelectionIndex]);
|
|
entryDwordLength = 2 + (entry->VariableLength + 3)/4;
|
|
base += 4*entryDwordLength;
|
|
}
|
|
|
|
|
|
bool waitForHaltActiveAfterConfigServerSettings = false;
|
|
// The "ME provisioning Halt/Activate" command must appear in the file only after "PKIDNSSuffix",
|
|
// "ConfigServerFQDN" and "Provisioning Server Address"
|
|
if ((pkiDnsSuffixFound || configServerFqdnFound || provisioningServerAddressFound) && meProvisioningHaltActivateFound)
|
|
{
|
|
waitForHaltActiveAfterConfigServerSettings = true;
|
|
}
|
|
|
|
for(unsigned int i = 0; i < numEntries; i++)
|
|
{
|
|
if(i == currPwdIndex || i == newPwdIndex || i == manSelectionIndex)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (i == meProvisioningHaltActivateIndex)
|
|
{
|
|
if (waitForHaltActiveAfterConfigServerSettings)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
entry = (DATA_RECORD_ENTRY_T*)(buffer + base);
|
|
SetEntry(entry, entries[i]);
|
|
if(modulesUsed)
|
|
{
|
|
modulesUsed->insert(entries[i].GetModuleId());
|
|
}
|
|
entryDwordLength = 2 + (entry->VariableLength + 3)/4;
|
|
base += 4*entryDwordLength;
|
|
}
|
|
|
|
// The "ME provisioning Halt/Activate" command must appear in the file only after "PKIDNSSuffix",
|
|
// "ConfigServerFQDN" and "Provisioning Server Address"
|
|
if (waitForHaltActiveAfterConfigServerSettings)
|
|
{
|
|
entry = (DATA_RECORD_ENTRY_T*)(buffer + base);
|
|
SetEntry(entry, entries[meProvisioningHaltActivateIndex]);
|
|
if(modulesUsed)
|
|
{
|
|
modulesUsed->insert(entries[meProvisioningHaltActivateIndex].GetModuleId());
|
|
}
|
|
entryDwordLength = 2 + (entry->VariableLength + 3)/4;
|
|
base += 4*entryDwordLength;
|
|
}
|
|
|
|
entry = (DATA_RECORD_ENTRY_T*)(buffer + base);
|
|
entry->ModuleIdentifier = 0;
|
|
entry->VariableIdentifier = 0;
|
|
entry->VariableLength = 0;
|
|
entry->Reserved = 0;
|
|
if (scrambled)
|
|
{
|
|
ScrambleRecordData(buffer + headerDwords, header->RecordChunkCount * CHUNK_SIZE - headerDwords);
|
|
}
|
|
|
|
return CONFIG_SUCCESS;
|
|
}
|
|
|
|
int BufferToRecords(const unsigned int bufferLength,
|
|
const unsigned char* buffer,
|
|
SetupFileInfo* fileData,
|
|
vector<DataRecord>* records)
|
|
{
|
|
if(buffer == NULL)
|
|
{
|
|
return CONFIG_INVALID_BUFFER;
|
|
}
|
|
|
|
SetupFileInfo tmp;
|
|
SetupFileInfo* fileInfo = (fileData ? fileData : &tmp);
|
|
|
|
unsigned int moduleListSize;
|
|
try
|
|
{
|
|
auto moduleList = std::unique_ptr<set<unsigned short>>(new set<unsigned short>());
|
|
int retVal = ParseFileHeader(bufferLength, buffer, fileInfo,
|
|
&moduleListSize, moduleList.get());
|
|
if (retVal != CONFIG_SUCCESS)
|
|
{
|
|
return retVal;
|
|
}
|
|
|
|
DataRecord record;
|
|
// verfiy the number of records consumed
|
|
for (unsigned int i = 0; i < fileInfo->recordsConsumed; i++)
|
|
{
|
|
retVal = GetDataRecord(fileInfo->dataRecordChunkCount,
|
|
(buffer + CHUNK_SIZE * (fileInfo->headerChunkCount + i*fileInfo->dataRecordChunkCount)),
|
|
fileInfo->majorVersion, fileInfo->minorVersion,
|
|
moduleList.get(), &record);
|
|
|
|
if (retVal != CONFIG_INVALID_RECORD)
|
|
{
|
|
return CONFIG_INVALID_FILE;
|
|
}
|
|
}
|
|
|
|
for (unsigned int i = fileInfo->recordsConsumed;
|
|
i < fileInfo->recordCount; i++)
|
|
{
|
|
retVal = GetDataRecord(fileInfo->dataRecordChunkCount,
|
|
(buffer + CHUNK_SIZE * (fileInfo->headerChunkCount + i*fileInfo->dataRecordChunkCount)),
|
|
fileInfo->majorVersion, fileInfo->minorVersion,
|
|
moduleList.get(), &record);
|
|
|
|
if (retVal == CONFIG_SUCCESS)
|
|
{
|
|
if (records)
|
|
{
|
|
records->push_back(record);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return retVal;
|
|
}
|
|
}
|
|
return CONFIG_SUCCESS;
|
|
}
|
|
catch (std::bad_alloc&)
|
|
{
|
|
printf("ERROR: can't allocate memory");
|
|
return MEMORY_ALLOC_ERROR;
|
|
}
|
|
}
|
|
|
|
int GetRecordByIndex(const unsigned int bufferLength,
|
|
const unsigned char* buffer,
|
|
const unsigned int index,
|
|
DataRecord* record)
|
|
{
|
|
if(buffer == NULL)
|
|
{
|
|
return CONFIG_INVALID_BUFFER;
|
|
}
|
|
SetupFileInfo fileInfo;
|
|
unsigned int moduleListSize;
|
|
|
|
try
|
|
{
|
|
auto moduleList = std::unique_ptr<set<unsigned short>>(new set<unsigned short>());
|
|
int retVal = ParseFileHeader(bufferLength, buffer, &fileInfo,
|
|
&moduleListSize, moduleList.get());
|
|
if (retVal != CONFIG_SUCCESS)
|
|
{
|
|
return retVal;
|
|
}
|
|
|
|
if (index == 0 || index > fileInfo.recordCount)
|
|
{
|
|
return CONFIG_INVALID_INDEX;
|
|
}
|
|
|
|
retVal = GetDataRecord(fileInfo.dataRecordChunkCount,
|
|
(buffer + CHUNK_SIZE * (fileInfo.headerChunkCount + (index - 1)*fileInfo.dataRecordChunkCount)),
|
|
fileInfo.majorVersion, fileInfo.minorVersion,
|
|
moduleList.get(), record);
|
|
return retVal;
|
|
}
|
|
catch (std::bad_alloc&)
|
|
{
|
|
printf("ERROR: can't allocate memory");
|
|
return MEMORY_ALLOC_ERROR;
|
|
}
|
|
}
|
|
|
|
int GetNextValidRecord(const unsigned int bufferLength,
|
|
const unsigned char* buffer,
|
|
DataRecord* record)
|
|
{
|
|
if(buffer == NULL)
|
|
{
|
|
return CONFIG_INVALID_BUFFER;
|
|
}
|
|
SetupFileInfo fileInfo;
|
|
unsigned int moduleListSize;
|
|
|
|
try
|
|
{
|
|
auto moduleList = std::unique_ptr<set<unsigned short>>(new set<unsigned short>());
|
|
int retVal = ParseFileHeader(bufferLength, buffer, &fileInfo,
|
|
&moduleListSize, moduleList.get());
|
|
if (retVal != CONFIG_SUCCESS)
|
|
{
|
|
return retVal;
|
|
}
|
|
|
|
if (fileInfo.recordsConsumed >= fileInfo.recordCount)
|
|
{
|
|
return CONFIG_NO_VALID_RECORDS;
|
|
}
|
|
|
|
unsigned int index = fileInfo.recordCount - fileInfo.recordsConsumed;
|
|
|
|
retVal = GetDataRecord(fileInfo.dataRecordChunkCount,
|
|
(buffer + CHUNK_SIZE * (fileInfo.headerChunkCount + (index - 1)*fileInfo.dataRecordChunkCount)),
|
|
fileInfo.majorVersion, fileInfo.minorVersion,
|
|
moduleList.get(), record);
|
|
|
|
if (retVal == CONFIG_INVALID_RECORD)
|
|
{
|
|
retVal = CONFIG_INVALID_FILE;
|
|
}
|
|
return retVal;
|
|
}
|
|
catch (std::bad_alloc&)
|
|
{
|
|
printf("ERROR: can't allocate memory");
|
|
return MEMORY_ALLOC_ERROR;
|
|
}
|
|
}
|
|
|
|
|
|
int RecordsToBuffer(const vector<DataRecord>& records,
|
|
const SetupFileInfo& setupInfo,
|
|
const unsigned int bufferLength,
|
|
unsigned char* buffer)
|
|
{
|
|
if(buffer == NULL)
|
|
{
|
|
return CONFIG_INVALID_BUFFER;
|
|
}
|
|
|
|
unsigned int numRecords = (unsigned int)records.size();
|
|
|
|
if((numRecords != setupInfo.recordCount) || (0 != setupInfo.recordsConsumed))
|
|
{
|
|
return CONFIG_INVALID_INPUT;
|
|
}
|
|
|
|
unsigned int requiredLength = (setupInfo.headerChunkCount + numRecords*setupInfo.dataRecordChunkCount)*CHUNK_SIZE;
|
|
if(bufferLength < requiredLength)
|
|
{
|
|
return CONFIG_INVALID_BUFFER_LENGTH;
|
|
}
|
|
|
|
set<unsigned short> modulesUsed;
|
|
|
|
int retVal = CONFIG_SUCCESS;
|
|
unsigned int index = 1;
|
|
unsigned int offset = CHUNK_SIZE * setupInfo.headerChunkCount;
|
|
|
|
try
|
|
{
|
|
auto tempBuffer = std::unique_ptr<unsigned char[]>(new unsigned char[requiredLength]);
|
|
memset(tempBuffer.get(), 0, requiredLength);
|
|
|
|
while (index <= numRecords)
|
|
{
|
|
retVal = WriteDataRecord(setupInfo.dataRecordChunkCount,
|
|
tempBuffer.get() + offset, setupInfo.majorVersion,
|
|
setupInfo.minorVersion, index, records[index - 1],
|
|
&modulesUsed);
|
|
if (retVal != CONFIG_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
offset += (CHUNK_SIZE * setupInfo.dataRecordChunkCount);
|
|
index++;
|
|
}
|
|
|
|
if (retVal == CONFIG_SUCCESS)
|
|
{
|
|
retVal = WriteFileHeader(tempBuffer.get(), setupInfo, modulesUsed);
|
|
}
|
|
if (retVal == CONFIG_SUCCESS)
|
|
{
|
|
if (memcpy_s(buffer, bufferLength, tempBuffer.get(), requiredLength))
|
|
{
|
|
return CONFIG_INVALID_BUFFER_LENGTH;
|
|
}
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
catch (std::bad_alloc&)
|
|
{
|
|
printf("ERROR: can't allocate memory");
|
|
return MEMORY_ALLOC_ERROR;
|
|
}
|
|
}
|
|
|
|
int GetChunkCount(const DataRecord& record)
|
|
{
|
|
unsigned int requiredDwords = (sizeof(DATA_RECORD_HEADER_T) + 3)/4;
|
|
|
|
vector<DataRecordEntry> entries = record.GetRecordEntries();
|
|
unsigned int numEntries = (unsigned int)entries.size();
|
|
|
|
for(int i = 0; i < (int)numEntries; i++)
|
|
{
|
|
requiredDwords += (2 + (entries[i].GetVariableLength() + 3)/4);
|
|
}
|
|
requiredDwords += 2; // for NULL terminating entry
|
|
|
|
return (4*requiredDwords + (CHUNK_SIZE - 1))/CHUNK_SIZE;
|
|
}
|