windows-nt/Source/XPSP1/NT/inetcore/digest/cred.cxx
2020-09-26 16:20:57 +08:00

808 lines
21 KiB
C++

/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
cred.cxx
Abstract:
Shared memory data structures for digest sspi package.
Author:
Adriaan Canter (adriaanc) 01-Aug-1998
--*/
#include "include.hxx"
//////////////////////////////////////////////////////////////////////
//
// CEntry Functions
//
//////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------
// CEntry::Free
// BUGBUG - inline this.
//--------------------------------------------------------------------
DWORD CEntry::Free(CMMFile *pMMFile, CEntry *pEntry)
{
BOOL bFree = pMMFile->FreeEntry(pEntry);
return (bFree ? ERROR_SUCCESS : ERROR_INTERNAL_ERROR);
}
//--------------------------------------------------------------------
// CEntry::GetNext
//--------------------------------------------------------------------
CEntry* CEntry::GetNext(CEntry *pEntry)
{
if (pEntry->dwNext)
return (CEntry*) OFFSET_TO_POINTER(g_pHeap, pEntry->dwNext);
return NULL;
}
//--------------------------------------------------------------------
// CEntry::GetPrev
//--------------------------------------------------------------------
CEntry* CEntry::GetPrev(CEntry *pEntry)
{
if (pEntry->dwPrev)
return (CEntry*) OFFSET_TO_POINTER(g_pHeap, pEntry->dwPrev);
return NULL;
}
//////////////////////////////////////////////////////////////////////
//
// CSess Functions
//
//////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------
// CSess::Create
//--------------------------------------------------------------------
CSess* CSess::Create(CMMFile *pMMFile,
LPSTR szAppCtx, LPSTR szUserCtx, BOOL fHTTP)
{
DIGEST_ASSERT(pMMFile);
// Unaligned Sess lengths.
DWORD cbAppCtx = szAppCtx ? strlen(szAppCtx) + 1 : 0;
DWORD cbUserCtx = szUserCtx ? strlen(szUserCtx) + 1 : 0;
// Aligned Sess lengths.
DWORD cbStructAligned = ROUNDUPDWORD(sizeof(CSess));
DWORD cbAppCtxAligned = ROUNDUPDWORD(cbAppCtx);
DWORD cbUserCtxAligned = ROUNDUPDWORD(cbUserCtx);
// Total number of required bytes (aligned).
DWORD cbEntryAligned = cbStructAligned
+ cbAppCtxAligned + cbUserCtxAligned;
// Allocate from mem map.
CSess *pSess = (CSess*) pMMFile->AllocateEntry(cbEntryAligned);
if (!pSess)
{
DIGEST_ASSERT(FALSE);
goto exit;
}
DWORD cbCurrentOffset;
cbCurrentOffset = cbStructAligned;
pSess->dwAppCtx = pSess->dwUserCtx = 0;
// AppCtx
if (szAppCtx)
{
memcpy(OFFSET_TO_POINTER(pSess, cbCurrentOffset), szAppCtx, cbAppCtx);
pSess->dwAppCtx = cbCurrentOffset;
cbCurrentOffset += cbAppCtxAligned;
}
// UserCtx
if (szUserCtx)
{
memcpy(OFFSET_TO_POINTER(pSess, cbCurrentOffset), szUserCtx, cbUserCtx);
pSess->dwUserCtx = cbCurrentOffset;
}
// No need to advance cbCurrentOffset.
pSess->cbSess = cbEntryAligned;
pSess->dwCred = 0;
pSess->dwSig = SIG_SESS;
pSess->fHTTP = fHTTP;
pSess->dwPrev = 0;
pSess->dwNext = 0;
exit:
return pSess;
}
//--------------------------------------------------------------------
// CSess::GetAppCtx
//--------------------------------------------------------------------
LPSTR CSess::GetAppCtx(CSess *pSess)
{
if (pSess->dwAppCtx)
return (LPSTR) OFFSET_TO_POINTER(pSess, pSess->dwAppCtx);
else
return NULL;
}
//--------------------------------------------------------------------
// CSess::GetUserCtx
//--------------------------------------------------------------------
LPSTR CSess::GetUserCtx(CSess *pSess)
{
if (pSess->dwUserCtx)
return (LPSTR) OFFSET_TO_POINTER(pSess, pSess->dwUserCtx);
else
return NULL;
}
//--------------------------------------------------------------------
// CSess::GetCtx
// Allocates a context string in local heap.
//--------------------------------------------------------------------
LPSTR CSess::GetCtx(CSess *pSess)
{
DIGEST_ASSERT(pSess);
LPSTR szAppCtx, szUserCtx, szCtx;
DWORD cbAppCtx, cbUserCtx, cbCtx;
szAppCtx = GetAppCtx(pSess);
szUserCtx = GetUserCtx(pSess);
cbAppCtx = szAppCtx ? strlen(szAppCtx) : 0;
cbUserCtx = szUserCtx ? strlen(szUserCtx) : 0;
cbCtx = cbAppCtx + sizeof(':') + cbUserCtx + sizeof('\0');
szCtx = new CHAR[cbCtx];
if (!szCtx)
{
DIGEST_ASSERT(FALSE);
return NULL;
}
// "appctx:userctx\0"
// bugbug - macro for sizeof -1
memcpy(szCtx, szAppCtx, cbAppCtx);
memcpy(szCtx + cbAppCtx, ":", sizeof(":") - 1);
memcpy(szCtx + cbAppCtx + sizeof(":") - 1, szUserCtx, cbUserCtx);
memcpy(szCtx + cbAppCtx + sizeof(":") - 1 + cbUserCtx, "\0", sizeof("\0") - 1);
return szCtx;
}
//--------------------------------------------------------------------
// CSess::CtxMatch
//--------------------------------------------------------------------
BOOL CSess::CtxMatch(CSess *pSess1, CSess *pSess2)
{
DIGEST_ASSERT(pSess1 && pSess2);
LPSTR szAppCtx1, szAppCtx2, szUserCtx1, szUserCtx2;
szAppCtx1 = CSess::GetAppCtx(pSess1);
szAppCtx2 = CSess::GetAppCtx(pSess2);
szUserCtx1 = CSess::GetUserCtx(pSess1);
szUserCtx2 = CSess::GetUserCtx(pSess2);
// If both AppCtx values are NULL or
// are equal to same string.
if ((!szAppCtx1 && !szAppCtx2)
|| ((szAppCtx1 && szAppCtx2)
&& !strcmp(szAppCtx1, szAppCtx2)))
{
// And both UserCtx values are NULL or
// are equal to same string.
if ((!szUserCtx1 && !szUserCtx2)
|| ((szUserCtx1 && szUserCtx2)
&& !strcmp(szUserCtx1, szUserCtx2)))
{
// Credentials are shareable.
return TRUE;
}
}
// Otherwise creds are not shareable.
return FALSE;
}
//--------------------------------------------------------------------
// CSess::GetCred
//--------------------------------------------------------------------
CCred *CSess::GetCred(CSess* pSess)
{
if (!pSess->dwCred)
return NULL;
return (CCred*) OFFSET_TO_POINTER(g_pHeap, pSess->dwCred);
}
//--------------------------------------------------------------------
// CSess::SetCred
//--------------------------------------------------------------------
CCred *CSess::SetCred(CSess* pSess, CCred* pCred)
{
if (!pCred)
pSess->dwCred = 0;
else
pSess->dwCred = POINTER_TO_OFFSET(g_pHeap, pCred);
return pCred;
}
//////////////////////////////////////////////////////////////////////
//
// CList Functions
//
//////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------
// CList::CList
//--------------------------------------------------------------------
CList::CList()
{
_pHead = NULL;
_pCur = NULL;
_pdwOffset = NULL;
}
//--------------------------------------------------------------------
// CList::Init
//--------------------------------------------------------------------
CEntry* CList::Init(LPDWORD pdwOffset)
{
DIGEST_ASSERT(pdwOffset)
_pdwOffset = pdwOffset;
if (*pdwOffset)
{
_pHead = (CEntry*) OFFSET_TO_POINTER(g_pHeap, *pdwOffset);
_pCur = _pHead;
}
return _pHead;
}
//--------------------------------------------------------------------
// CList::Seek
//--------------------------------------------------------------------
CEntry* CList::Seek()
{
// DIGEST_ASSERT(_pHead);
_pHead = (CEntry*) OFFSET_TO_POINTER(g_pHeap, *_pdwOffset);
_pCur = _pHead;
return _pCur;
}
//--------------------------------------------------------------------
// CList::GetNext
//--------------------------------------------------------------------
CEntry* CList::GetNext()
{
if (! *_pdwOffset)
return NULL;
CEntry *pEntry = _pCur;
if (_pCur)
_pCur = _pCur->dwNext ?
(CEntry*) OFFSET_TO_POINTER(g_pHeap, _pCur->dwNext) : NULL;
return pEntry;
}
//--------------------------------------------------------------------
// CList::GetPrev
//--------------------------------------------------------------------
CEntry* CList::GetPrev()
{
if (! *_pdwOffset)
return NULL;
CEntry *pEntry = _pCur;
if (_pCur)
_pCur = _pCur->dwPrev ?
(CEntry*) OFFSET_TO_POINTER(g_pHeap, _pCur->dwPrev) : NULL;
return pEntry;
}
//--------------------------------------------------------------------
// CList::Insert
//--------------------------------------------------------------------
CEntry* CList::Insert(CEntry *pEntry)
{
// BUGBUG - assert pnext pprev are null
DIGEST_ASSERT(pEntry
&& (pEntry->dwPrev == pEntry->dwNext == 0));
if (!_pHead)
{
_pHead = pEntry;
}
else
{
pEntry->dwNext = POINTER_TO_OFFSET(g_pHeap, _pHead);
_pHead->dwPrev = POINTER_TO_OFFSET(g_pHeap, pEntry);
_pHead = pEntry;
}
*_pdwOffset = POINTER_TO_OFFSET(g_pHeap, pEntry);
return pEntry;
}
//--------------------------------------------------------------------
// CList::DeLink
//--------------------------------------------------------------------
CEntry* CList::DeLink(CEntry *pEntry)
{
DIGEST_ASSERT(pEntry);
if (pEntry == _pHead)
{
_pHead = (CEntry*) OFFSET_TO_POINTER(g_pHeap, pEntry->dwNext);
*_pdwOffset = POINTER_TO_OFFSET(g_pHeap, _pHead);
}
else
{
CEntry *pPrev;
pPrev = (CEntry*) OFFSET_TO_POINTER(g_pHeap, pEntry->dwPrev);
pPrev->dwNext = pEntry->dwNext;
}
if (pEntry->dwNext)
{
CEntry *pNext;
pNext = (CEntry*) OFFSET_TO_POINTER(g_pHeap, pEntry->dwNext);
pNext->dwPrev = pEntry->dwPrev;
}
if (_pCur == pEntry)
{
_pCur = (CEntry*) OFFSET_TO_POINTER(g_pHeap, pEntry->dwNext);
}
return pEntry;
}
//////////////////////////////////////////////////////////////////////
//
// CCred Functions
//
//////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------
// CCred::Create
//--------------------------------------------------------------------
CCred* CCred::Create(CMMFile *pMMFile,
LPSTR szHost, LPSTR szRealm, LPSTR szUser,
LPSTR szPass, LPSTR szNonce, LPSTR szCNonce)
{
// BUGBUG - assert strings non-null. Nonce can be NULL.
DIGEST_ASSERT(pMMFile && szRealm && szUser && szPass);
// Unaligned string sizes.
DWORD cbRealm = szRealm ? strlen(szRealm) + 1 : 0;
DWORD cbUser = szUser ? strlen(szUser) + 1 : 0;
DWORD cbPass = szPass ? strlen(szPass) + 1 : 0;
// Aligned string sizes.
DWORD cbStructAligned = ROUNDUPDWORD(sizeof(CCred));
DWORD cbRealmAligned = ROUNDUPDWORD(cbRealm);
DWORD cbUserAligned = ROUNDUPDWORD(cbUser);
DWORD cbPassAligned = ROUNDUPDWORD(cbPass);
// Total number of required bytes (aligned).
DWORD cbEntryAligned = cbStructAligned
+ cbRealmAligned
+ cbUserAligned
+ cbPassAligned;
// Allocate cred and nonce from memmap
// BUGBUG - MASKING PNONCE
// BUGBUG - no, I'm not.
CCred *pCred;
CNonce *pNonce, *pCNonce;
pNonce = pCNonce = NULL;
// Allocate a credential.
pCred = (CCred*) pMMFile->AllocateEntry(cbEntryAligned);
if (!pCred)
{
DIGEST_ASSERT(FALSE);
goto exit;
}
DWORD cbCurrentOffset;
cbCurrentOffset = cbStructAligned;
// Realm.
memcpy(OFFSET_TO_POINTER(pCred, cbCurrentOffset), szRealm, cbRealm);
pCred->dwRealm = cbCurrentOffset;
cbCurrentOffset += cbRealmAligned;
// User
memcpy(OFFSET_TO_POINTER(pCred, cbCurrentOffset), szUser, cbUser);
pCred->dwUser = cbCurrentOffset;
cbCurrentOffset += cbUserAligned;
// Pass
memcpy(OFFSET_TO_POINTER(pCred, cbCurrentOffset), szPass, cbPass);
pCred->dwPass = cbCurrentOffset;
pCred->cbCred = cbEntryAligned;
pCred->tStamp = GetTickCount();
pCred->dwSig = SIG_CRED;
pCred->dwPrev = NULL;
pCred->dwNext = NULL;
pCred->dwNonce = 0;
pCred->dwCNonce = 0;
// Allocate nonce and client nonce if specified.
if (szNonce)
CCred::SetNonce(pMMFile, pCred, szHost, szNonce, SERVER_NONCE);
if (szCNonce)
CCred::SetNonce(pMMFile, pCred, szHost, szCNonce, CLIENT_NONCE);
exit:
return pCred;
}
//--------------------------------------------------------------------
// CCred::GetRealm
//--------------------------------------------------------------------
LPSTR CCred::GetRealm(CCred* pCred)
{
DIGEST_ASSERT(pCred);
if (pCred->dwRealm)
return (LPSTR) OFFSET_TO_POINTER(pCred, pCred->dwRealm);
else
return NULL;
}
//--------------------------------------------------------------------
// CCred::GetUser
//--------------------------------------------------------------------
LPSTR CCred::GetUser(CCred* pCred)
{
DIGEST_ASSERT(pCred);
if (pCred->dwUser)
return (LPSTR) OFFSET_TO_POINTER(pCred, pCred->dwUser);
else
return NULL;
}
//--------------------------------------------------------------------
// CCred::GetPass
//--------------------------------------------------------------------
LPSTR CCred::GetPass(CCred* pCred)
{
DIGEST_ASSERT(pCred);
if (pCred->dwPass)
return (LPSTR) OFFSET_TO_POINTER(pCred, pCred->dwPass);
else
return NULL;
}
//--------------------------------------------------------------------
// CCred::SetNonce
//--------------------------------------------------------------------
VOID CCred::SetNonce(CMMFile *pMMFile, CCred* pCred,
LPSTR szHost, LPSTR szNonce, DWORD dwType)
{
DIGEST_ASSERT(pCred && szNonce);
// First determine if a nonce for the specified host
// already exists and delete it if it does.
CList NonceList;
NonceList.Init(dwType == SERVER_NONCE ?
&pCred->dwNonce : &pCred->dwCNonce);
CNonce *pNonce;
while (pNonce = (CNonce*) NonceList.GetNext())
{
if (CNonce::IsHostMatch(pNonce, szHost))
{
NonceList.DeLink(pNonce);
CEntry::Free(pMMFile, pNonce);
break;
}
}
// Create a CNonce object and insert it into the list.
pNonce = CNonce::Create(pMMFile, szHost, szNonce);
if (pNonce)
{
NonceList.Seek();
NonceList.Insert(pNonce);
}
else
{
DIGEST_ASSERT(FALSE);
}
}
//--------------------------------------------------------------------
// CCred::GetNonce
//--------------------------------------------------------------------
CNonce *CCred::GetNonce(CCred* pCred, LPSTR szHost, DWORD dwType)
{
CNonce *pNonce;
CList NonceList;
NonceList.Init(dwType == SERVER_NONCE ?
&pCred->dwNonce : &pCred->dwCNonce);
while (pNonce = (CNonce*) NonceList.GetNext())
{
if (CNonce::IsHostMatch(pNonce, szHost))
break;
}
return pNonce;
}
//--------------------------------------------------------------------
// CCred::Free
//--------------------------------------------------------------------
VOID CCred::Free(CMMFile *pMMFile, CSess *pSess, CCred *pCred)
{
CNonce *pNonce;
CList NonceList;
// Free up server nonce.
NonceList.Init(&pCred->dwNonce);
while (pNonce = (CNonce*) NonceList.GetNext())
{
NonceList.DeLink(pNonce);
CEntry::Free(pMMFile, pNonce);
}
// Free up client nonce.
NonceList.Init(&pCred->dwCNonce);
while (pNonce = (CNonce*) NonceList.GetNext())
{
NonceList.DeLink(pNonce);
CEntry::Free(pMMFile, pNonce);
}
// Remove credential from session's list.
CList CredList;
CredList.Init(&pSess->dwCred);
CredList.DeLink(pCred);
CEntry::Free(pMMFile, pCred);
}
//////////////////////////////////////////////////////////////////////
//
// CNonce Functions
//
//////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------
// CNonce::Create
//--------------------------------------------------------------------
CNonce* CNonce::Create(CMMFile *pMMFile, LPSTR szHost, LPSTR szNonce)
{
DIGEST_ASSERT(pMMFile && szNonce);
// Unaligned string sizes.
DWORD cbNonce = szNonce ? strlen(szNonce) + 1 : 0;
DWORD cbHost = szHost ? strlen(szHost) + 1 : 0;
// Aligned string sizes.
DWORD cbStructAligned = ROUNDUPDWORD(sizeof(CNonce));
DWORD cbNonceAligned = ROUNDUPDWORD(cbNonce);
DWORD cbHostAligned = ROUNDUPDWORD(cbHost);
// Total number of required bytes (aligned).
DWORD cbEntryAligned = cbStructAligned
+ cbHostAligned
+ cbNonceAligned;
// Allocate from mem map.
CNonce *pNonce = (CNonce*) pMMFile->AllocateEntry(cbEntryAligned);
// Failed to allocate.
if (!pNonce)
{
DIGEST_ASSERT(FALSE);
goto exit;
}
DWORD cbCurrentOffset;
cbCurrentOffset = cbStructAligned;
// Host.
if (szHost)
{
memcpy(OFFSET_TO_POINTER(pNonce, cbCurrentOffset), szHost, cbHost);
pNonce->dwHost = cbCurrentOffset;
cbCurrentOffset += cbHostAligned;
}
else
{
pNonce->dwHost = 0;
}
// Nonce.
memcpy(OFFSET_TO_POINTER(pNonce, cbCurrentOffset), szNonce, cbNonce);
pNonce->dwNonce = cbCurrentOffset;
cbCurrentOffset += cbNonceAligned;
pNonce->cbNonce = cbEntryAligned;
pNonce->cCount = 0;
pNonce->dwSig = SIG_NONC;
pNonce->dwPrev = 0;
pNonce->dwNext = 0;
exit:
return pNonce;
}
//--------------------------------------------------------------------
// CNonce::GetNonce
//--------------------------------------------------------------------
LPSTR CNonce::GetNonce(CNonce* pNonce)
{
if (pNonce && pNonce->dwNonce)
return (LPSTR) OFFSET_TO_POINTER(pNonce, pNonce->dwNonce);
else
return NULL;
}
//--------------------------------------------------------------------
// CNonce::GetCount
// bugbug - what if no nonce?
//--------------------------------------------------------------------
DWORD CNonce::GetCount(CNonce* pNonce)
{
DIGEST_ASSERT(pNonce);
return pNonce->cCount;
}
//--------------------------------------------------------------------
// CNonce::IsHostMatch
//--------------------------------------------------------------------
BOOL CNonce::IsHostMatch(CNonce *pNonce, LPSTR szHost)
{
if (szHost)
{
if (pNonce->dwHost
&& !strcmp(szHost, (LPSTR) OFFSET_TO_POINTER(pNonce, pNonce->dwHost)))
return TRUE;
return FALSE;
}
if (!pNonce->dwHost)
return TRUE;
return FALSE;
}
//////////////////////////////////////////////////////////////////////
//
// CCredInfo Functions
//
//////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------
// CCredInfo::CCredInfo
//--------------------------------------------------------------------
CCredInfo::CCredInfo(CCred* pCred, LPSTR szHost)
{
DIGEST_ASSERT(pCred
&& (pCred->dwPass > pCred->dwUser)
&& (pCred->dwUser > pCred->dwRealm));
CCredInfo::szHost = NewString(szHost);
szRealm = NewString(CCred::GetRealm(pCred));
szUser = NewString(CCred::GetUser(pCred));
szPass = NewString(CCred::GetPass(pCred));
// Get server nonce. This is always required.
// BUGBUG - what about pre-loading?
CNonce *pNonce;
pNonce = CCred::GetNonce(pCred, szHost, SERVER_NONCE);
if (!pNonce)
{
dwStatus = ERROR_INVALID_PARAMETER;
return;
}
szNonce = NewString(CNonce::GetNonce(pNonce));
cCount = pNonce->cCount;
pNonce = CCred::GetNonce(pCred, szHost, CLIENT_NONCE);
if (pNonce)
szCNonce = NewString(CNonce::GetNonce(pNonce));
else
szCNonce = NULL;
tStamp = pCred->tStamp;
pPrev = NULL;
pNext = NULL;
dwStatus = ERROR_SUCCESS;
}
//--------------------------------------------------------------------
// CCredInfo::CCredInfo
// BUGBUG - special casing for NULLs, especially szNonce.
//--------------------------------------------------------------------
CCredInfo::CCredInfo(LPSTR szHost, LPSTR szRealm, LPSTR szUser,
LPSTR szPass, LPSTR szNonce, LPSTR szCNonce)
{
CCredInfo::szHost = NewString(szHost);
CCredInfo::szRealm = NewString(szRealm);
CCredInfo::szUser = NewString(szUser);
CCredInfo::szPass = NewString(szPass);
CCredInfo::szNonce = NewString(szNonce);
CCredInfo::szCNonce = NewString(szCNonce);
cCount = 0;
tStamp = 0;
pPrev = NULL;
pNext = NULL;
dwStatus = ERROR_SUCCESS;
}
//--------------------------------------------------------------------
// CCredInfo::~CCredInfo
//--------------------------------------------------------------------
CCredInfo::~CCredInfo()
{
if (szHost)
delete [] szHost;
if (szRealm)
delete [] szRealm;
if (szUser)
delete [] szUser;
if (szPass)
delete [] szPass;
if (szNonce)
delete [] szNonce;
if (szCNonce)
delete [] szCNonce;
}