537 lines
13 KiB
C++
537 lines
13 KiB
C++
/*++
|
|
|
|
Copyright (c) 2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ticketSchema.cpp
|
|
|
|
Abstract:
|
|
|
|
Implementation of ticket schema lookup
|
|
|
|
Usage:
|
|
|
|
Author:
|
|
|
|
Wei Jiang(weijiang) 15-Jan-2001
|
|
|
|
Revision History:
|
|
15-Jan-2001 weijiang Created.
|
|
|
|
--*/
|
|
|
|
#include "stdafx.h"
|
|
#include "ticketschema.h"
|
|
#include "BstrDebug.h"
|
|
#include <winsock2.h> // u_short, u_long, ntohs, ntohl
|
|
#include <crtdbg.h>
|
|
#include <pmerrorcodes.h>
|
|
#include <time.h>
|
|
// #include <pmalerts.h>
|
|
|
|
#define PASSPORTLOG(i,x) ;
|
|
|
|
CTicketSchema::CTicketSchema()
|
|
: m_isOk(FALSE), m_szReason(L"Uninitialized"),
|
|
m_numAtts(0), m_attsDef(NULL), m_version(0)
|
|
{
|
|
}
|
|
|
|
CTicketSchema::~CTicketSchema()
|
|
{
|
|
if (m_attsDef != NULL)
|
|
delete[] m_attsDef;
|
|
}
|
|
|
|
BOOL CTicketSchema::ReadSchema(MSXML::IXMLElementPtr &root)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
LPTSTR r=NULL; // The current error, if it happens
|
|
int cAtts = 0;
|
|
MSXML::IXMLElementCollectionPtr atts;
|
|
MSXML::IXMLElementPtr pElt;
|
|
VARIANT iAtts;
|
|
|
|
// Type identifiers
|
|
|
|
try
|
|
{
|
|
// Ok, now iterate over attributes
|
|
atts = root->children;
|
|
cAtts = atts->length;
|
|
|
|
if (cAtts <= 0)
|
|
{
|
|
r = _T("No attributes in TicketSchema file.");
|
|
_com_issue_error(E_FAIL);
|
|
}
|
|
|
|
if (m_attsDef)
|
|
delete[] m_attsDef;
|
|
|
|
m_attsDef = new TicketFieldDef[cAtts];
|
|
|
|
// get name and version info
|
|
m_name = root->getAttribute(ATTRNAME_NAME);
|
|
_bstr_t aVersion = root->getAttribute(ATTRNAME_VERSION);
|
|
|
|
if(aVersion.length() != 0)
|
|
m_version = (short)_wtol(aVersion);
|
|
else
|
|
m_version = 0; // invalid
|
|
|
|
VariantInit(&iAtts);
|
|
iAtts.vt = VT_I4;
|
|
|
|
for (iAtts.lVal = 0; iAtts.lVal < cAtts; iAtts.lVal++)
|
|
{
|
|
pElt = atts->item(iAtts);
|
|
m_attsDef[iAtts.lVal].name = pElt->getAttribute(ATTRNAME_NAME);
|
|
_bstr_t aType = pElt->getAttribute(ATTRNAME_TYPE);
|
|
_bstr_t aFlags = pElt->getAttribute(ATTRNAME_FLAGS);
|
|
|
|
// find out the type information
|
|
m_attsDef[iAtts.lVal].type = tInvalid;
|
|
if(aType.length() != 0)
|
|
{
|
|
for(int i = 0; i < (sizeof(TicketTypeNameMap) / sizeof(CTicketTypeNameMap)); ++i)
|
|
{
|
|
if(_wcsicmp(aType, TicketTypeNameMap[i].name) == 0)
|
|
{
|
|
m_attsDef[iAtts.lVal].type = TicketTypeNameMap[i].type;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// flags
|
|
if(aFlags.length() != 0)
|
|
m_attsDef[iAtts.lVal].flags = _wtol(aFlags);
|
|
else
|
|
m_attsDef[iAtts.lVal].flags = 0;
|
|
}
|
|
|
|
m_numAtts = iAtts.lVal;
|
|
bResult = m_isOk = TRUE;
|
|
|
|
}
|
|
catch (_com_error &e)
|
|
{
|
|
CHAR ach[256];
|
|
|
|
// TODO -- put tracing code in to ease the debug
|
|
WideCharToMultiByte(CP_ACP, 0, e.ErrorMessage(), -1, ach, sizeof(ach), NULL, NULL);
|
|
PASSPORTLOG(DOMAINMAP_DBGNUM, "Passport: CTicketSchema::Read threw this exception: \""<<ach<<"\".\n");
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, r, -1, ach, sizeof(ach), NULL, NULL);
|
|
PASSPORTLOG(DOMAINMAP_DBGNUM, "Passport: CTicketSchema::Read...r = \""<<ach<<"\".\n");
|
|
|
|
bResult = m_isOk = FALSE;
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
HRESULT CTicketSchema::parseTicket(LPCSTR raw, UINT size, CTicketPropertyBag& bag)
|
|
{
|
|
DWORD cParsed = 0;
|
|
HRESULT hr = S_OK;
|
|
LPBYTE dataToParse = (LPBYTE)raw;
|
|
UINT cDataToParse = size;
|
|
|
|
#if 0 // avoid changing to much to the code, not to deal with the 1.3x ticket format in schema parser
|
|
// get those 1.3X items
|
|
CTicket_13X ticket13X;
|
|
|
|
// parse the 1.3X ticket first
|
|
BOOL bParsed = ticket13X.parse(dataToParse, cDataToParse, &cParsed);
|
|
|
|
if (!bParsed) return E_INVALIDARG;
|
|
|
|
{
|
|
long curTime;
|
|
|
|
time(&curTime);
|
|
// If the current time is "too" negative, bail (5 mins)
|
|
if ((unsigned long)(curTime+300) < ticket13X.currentTime())
|
|
{
|
|
/*
|
|
if (g_pAlert)
|
|
{
|
|
DWORD dwTimes[2] = { curTime, ntohl(*(u_long*) (lpBase+spot)) };
|
|
g_pAlert->report(PassportAlertInterface::ERROR_TYPE, PM_TIMESTAMP_BAD,
|
|
0, NULL, sizeof(DWORD) << 1, (LPVOID)dwTimes);
|
|
}
|
|
*/
|
|
hr = E_FAIL; // need an error code for ... PM_TIMESTAMP_BAD;
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
dataToParse += cParsed;
|
|
cDataToParse -= cParsed;
|
|
// put 1.3x fields into the bag
|
|
// TODO -- later
|
|
#endif // 1.3X stuff
|
|
|
|
// then the schema version #
|
|
if(cDataToParse > 2) // enough for version
|
|
{
|
|
unsigned short * p = (unsigned short *)(dataToParse);
|
|
#if 0 // we purposely not to compare version, since live prop may create a time gap there between mspp, and parnter site.
|
|
if (ntohs(*p) != m_version)
|
|
return S_FALSE; // Todo -- new error code for version mismatch
|
|
#endif
|
|
|
|
if (m_version < VALID_SCHEMA_VERSION_MIN || m_version > VALID_SCHEMA_VERSION_MAX)
|
|
return S_FALSE; // not able to process with this version of ppm
|
|
|
|
dataToParse += 2;
|
|
cDataToParse -= 2;
|
|
}
|
|
|
|
// then the maskK
|
|
CTicketFieldMasks maskF;
|
|
hr = maskF.Parse(dataToParse, cDataToParse, &cParsed);
|
|
|
|
if(hr != S_OK)
|
|
return hr;
|
|
|
|
// pointer advances
|
|
dataToParse += cParsed;
|
|
cDataToParse -= cParsed;
|
|
|
|
USHORT* pIndexes = maskF.GetIndexes();
|
|
DWORD type = 0;
|
|
DWORD flags = 0;
|
|
DWORD fSize = 0;
|
|
variant_t value;
|
|
|
|
USHORT index = MASK_INDEX_INVALID;
|
|
// then the data
|
|
// get items that enabled by the schema
|
|
while((index = *pIndexes) != MASK_INDEX_INVALID && cDataToParse > 0)
|
|
{
|
|
TicketProperty prop;
|
|
// if index is out of schema range
|
|
if (index >= m_numAtts) break;
|
|
|
|
// fill-in the offset of the property
|
|
prop.offset = dataToParse - (LPBYTE)raw;
|
|
|
|
// type
|
|
type = m_attsDef[index].type;
|
|
|
|
fSize = TicketTypeSizes[type];
|
|
switch (type)
|
|
{
|
|
case tText:
|
|
{
|
|
u_short slen = ntohs(*(u_short*)(dataToParse));
|
|
value.vt = VT_BSTR;
|
|
if (slen == 0)
|
|
{
|
|
value.bstrVal = ALLOC_AND_GIVEAWAY_BSTR_LEN(L"", 0);
|
|
}
|
|
else
|
|
{
|
|
int wlen = MultiByteToWideChar(CP_UTF8, 0,
|
|
(LPCSTR)dataToParse+sizeof(u_short),
|
|
slen, NULL, 0);
|
|
value.bstrVal = ALLOC_AND_GIVEAWAY_BSTR_LEN(NULL, wlen);
|
|
MultiByteToWideChar(CP_UTF8, 0,
|
|
(LPCSTR)dataToParse+sizeof(u_short),
|
|
slen, value.bstrVal, wlen);
|
|
value.bstrVal[wlen] = L'\0';
|
|
}
|
|
|
|
dataToParse += slen + sizeof(u_short);
|
|
cDataToParse -= slen + sizeof(u_short);
|
|
}
|
|
break;
|
|
|
|
case tChar:
|
|
_ASSERTE(0); // NEED MORE THOUGHT -- IF unicode makes more sense
|
|
/*
|
|
{
|
|
int wlen = MultiByteToWideChar(CP_UTF8, 0,
|
|
raw+m_pos[index],
|
|
m_schema->GetByteSize(index), NULL, 0);
|
|
pVal->vt = VT_BSTR;
|
|
pVal->bstrVal = ALLOC_AND_GIVEAWAY_BSTR_LEN(NULL, wlen);
|
|
MultiByteToWideChar(CP_UTF8, 0,
|
|
raw+m_pos[index],
|
|
m_schema->GetByteSize(index), pVal->bstrVal, wlen);
|
|
pVal->bstrVal[wlen] = L'\0';
|
|
}
|
|
*/
|
|
break;
|
|
case tByte:
|
|
value.vt = VT_I2;
|
|
value.iVal = *(BYTE*)(dataToParse);
|
|
break;
|
|
case tWord:
|
|
value.vt = VT_I2;
|
|
value.iVal = ntohs(*(u_short*) (dataToParse));
|
|
break;
|
|
case tLong:
|
|
value.vt = VT_I4;
|
|
value.lVal = ntohl(*(u_long*) (dataToParse));
|
|
break;
|
|
case tDate:
|
|
value.vt = VT_DATE;
|
|
VarDateFromI4(ntohl(*(u_long*) (dataToParse)), &(value.date));
|
|
break;
|
|
default:
|
|
return PP_E_BAD_DATA_FORMAT;
|
|
}
|
|
|
|
// now with name, flags, value, type, we can put it into property bag
|
|
// name, flags, value
|
|
prop.flags = m_attsDef[index].flags;
|
|
prop.type = type;
|
|
prop.value.Attach(value.Detach());
|
|
bag.PutProperty(m_attsDef[index].name, prop);
|
|
|
|
|
|
// for text data, the pointer was already adjusted
|
|
if (fSize != SIZE_TEXT)
|
|
{
|
|
dataToParse += fSize;
|
|
cDataToParse -= fSize;
|
|
}
|
|
|
|
++pIndexes;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
//
|
|
// Ticket property bag
|
|
//
|
|
CTicketPropertyBag::CTicketPropertyBag()
|
|
{
|
|
|
|
}
|
|
|
|
CTicketPropertyBag::~CTicketPropertyBag()
|
|
{
|
|
}
|
|
|
|
HRESULT CTicketPropertyBag::GetProperty(LPCWSTR name, TicketProperty& prop)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if(!name || (!*name))
|
|
return E_INVALIDARG;
|
|
|
|
TicketPropertyMap::iterator i;
|
|
|
|
i = m_props.find(name);
|
|
|
|
if(i!= m_props.end())
|
|
prop = i->second;
|
|
else
|
|
hr = S_FALSE;
|
|
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CTicketPropertyBag::PutProperty(LPCWSTR name, const TicketProperty& prop)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if(!name || (!*name))
|
|
return E_INVALIDARG;
|
|
try{
|
|
m_props[name] = prop;
|
|
}
|
|
catch (...)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
#if 0 // was meant to replace existing code that parses the 1.3x ticket -- to avoid too much change, not to use it for now.
|
|
|
|
//
|
|
// deal with 1.3X ticket format
|
|
//
|
|
BOOL CTicket_13X::parse(
|
|
LPBYTE raw,
|
|
DWORD dwByteLen,
|
|
DWORD* pdwBytesParsed
|
|
)
|
|
{
|
|
LPSTR lpBase;
|
|
UINT byteLen, spot=0;
|
|
long curTime;
|
|
|
|
if(pdwBytesParsed)
|
|
*pdwBytesParsed = 0;
|
|
|
|
m_valid = false;
|
|
if (!raw)
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
// format:
|
|
// four bytes network long - low memberId bytes
|
|
// four bytes network long - high memberId bytes
|
|
// four bytes network long - time of last refresh
|
|
// four bytes network long - time of last password entry
|
|
// four bytes network long - time of ticket generation
|
|
// one byte - is this a saved password (Y/N)
|
|
// four bytes network long - flags
|
|
|
|
lpBase = (LPSTR) raw;
|
|
byteLen = dwByteLen;
|
|
spot=0;
|
|
|
|
if (byteLen < sizeof(u_long)*5 + sizeof(char))
|
|
{
|
|
m_valid = FALSE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
m_mIdLow = ntohl(*(u_long*)lpBase);
|
|
spot += sizeof(u_long);
|
|
|
|
m_mIdHigh = ntohl(*(u_long*)(lpBase + spot));
|
|
spot += sizeof(u_long);
|
|
|
|
m_ticketTime = ntohl(*(u_long*) (lpBase+spot));
|
|
spot += sizeof(u_long);
|
|
|
|
m_lastSignInTime = ntohl(*(u_long*) (lpBase+spot));
|
|
spot += sizeof(u_long);
|
|
|
|
time(&curTime);
|
|
// If the current time is "too" negative, bail (5 mins)
|
|
m_curTime = ntohl(*(u_long*) (lpBase+spot));
|
|
spot += sizeof(u_long);
|
|
|
|
m_savedPwd = (*(char*)(lpBase+spot)) == 'Y' ? TRUE : FALSE;
|
|
spot += sizeof(char);
|
|
|
|
m_flags = ntohl(*(u_long*) (lpBase+spot));
|
|
spot += sizeof(u_long);
|
|
|
|
m_valid = TRUE;
|
|
*pdwBytesParsed = spot;
|
|
|
|
Cleanup:
|
|
|
|
return m_valid;
|
|
}
|
|
|
|
ULONG CTicket_13X::ticketTime()
|
|
{
|
|
return m_ticketTime;
|
|
}
|
|
|
|
ULONG CTicket_13X::currentTime()
|
|
{
|
|
return m_curTime;
|
|
}
|
|
|
|
ULONG CTicket_13X::signInTime()
|
|
{
|
|
return m_lastSignInTime;
|
|
}
|
|
|
|
ULONG CTicket_13X::flags()
|
|
{
|
|
return m_flags;
|
|
}
|
|
|
|
ULONG CTicket_13X::memberIdHigh()
|
|
{
|
|
return m_mIdHigh;
|
|
}
|
|
|
|
ULONG CTicket_13X::memberIdLow()
|
|
{
|
|
return m_mIdLow;
|
|
}
|
|
|
|
BOOL CTicket_13X::hasSavedPassword()
|
|
{
|
|
return m_savedPwd;
|
|
}
|
|
|
|
BOOL CTicket_13X::isValid()
|
|
{
|
|
return m_valid;
|
|
}
|
|
|
|
#endif // if 0 ...
|
|
//
|
|
//
|
|
// class CTicketFieldMasks
|
|
//
|
|
inline HRESULT CTicketFieldMasks::Parse(PBYTE masks, ULONG size, ULONG* pcParsed) throw()
|
|
{
|
|
_ASSERT(pcParsed && masks);
|
|
// 16 bits as a unit of masks
|
|
|
|
*pcParsed = 0;
|
|
if (!masks || size < 2) return E_INVALIDARG;
|
|
// validate the masks
|
|
u_short* p = (u_short*)masks;
|
|
ULONG totalMasks = 15;
|
|
u_short mask;
|
|
*pcParsed += 2;
|
|
|
|
// find out size
|
|
while(MORE_MASKUNIT(ntohs(*p++))) //the folling short is mask unit
|
|
{
|
|
totalMasks += 15;
|
|
// insufficient data in buffer
|
|
if (*pcParsed + 2 > size) return E_INVALIDARG;
|
|
|
|
*pcParsed += 2;
|
|
}
|
|
|
|
if(m_fieldIndexes) delete[] m_fieldIndexes;
|
|
m_fieldIndexes = new unsigned short[totalMasks]; // max number of mask bits
|
|
for ( unsigned int i = 0; i < totalMasks; ++i)
|
|
{
|
|
m_fieldIndexes[i] = MASK_INDEX_INVALID;
|
|
}
|
|
|
|
p = (u_short*)masks;
|
|
unsigned short index = 0;
|
|
totalMasks = 0;
|
|
// fill in the mask
|
|
do
|
|
{
|
|
mask = ntohs(*p++);
|
|
//// find the bits
|
|
if (mask & 0x7fff) // any 1s
|
|
{
|
|
unsigned short j = 0x0001;
|
|
while( j != 0x8000 )
|
|
{
|
|
if(j & mask)
|
|
m_fieldIndexes[totalMasks++] = index;
|
|
++index;
|
|
j <<= 1;
|
|
}
|
|
}
|
|
else
|
|
index += 15;
|
|
} while(MORE_MASKUNIT(mask)); //the folling short is mask unit
|
|
|
|
|
|
return S_OK;
|
|
}
|
|
|