|
|
/************************************************************************************************
Copyright (c) 2001 Microsoft Corporation
File Name: NTAuth.cpp Abstract: Implementation of CAuthServer class to do NTLM/Kerberos authentication Notes: History: 10/10/2001 Created by Hao Yu (haoyu)
************************************************************************************************/
#include "stdafx.h"
#include "NTAuth.h"
#include "uuencode.h"
#include <atlbase.h>
//Initialize static members
long CAuthServer::m_glInit=0; PSecurityFunctionTable CAuthServer::m_gpFuncs=NULL; HINSTANCE CAuthServer::m_ghLib=NULL; IP3Config *CAuthServer::m_gpIConfig=NULL;
//Static fuction to load SSPI Provider function table
HRESULT CAuthServer::GlobalInit() { HRESULT hr=S_OK; FARPROC pInit=NULL; PSecPkgInfo pPkgInfo; if( 0==InterlockedCompareExchange(&m_glInit, 2, 0)) { //Initialization needed
TCHAR tszWinDir[MAX_PATH+sizeof(NT_SEC_DLL_NAME)+1]; if(0!=GetWindowsDirectory(tszWinDir, MAX_PATH+1)) { tszWinDir[MAX_PATH]=0; _tcscat(tszWinDir, NT_SEC_DLL_NAME ); m_ghLib=LoadLibrary(tszWinDir); if(NULL == m_ghLib) { hr=HRESULT_FROM_WIN32(GetLastError()); } } else { hr=E_FAIL; } if(S_OK==hr) { pInit=GetProcAddress(m_ghLib, SECURITY_ENTRYPOINT_ANSI); if(NULL == pInit) { hr=HRESULT_FROM_WIN32(GetLastError()); } }
if(S_OK==hr) { m_gpFuncs = (PSecurityFunctionTable) pInit(); if(NULL == m_gpFuncs) { hr=HRESULT_FROM_WIN32(GetLastError()); } } if(S_OK==hr) { //Make sure the security package is available
if(SEC_SUCCESS(m_gpFuncs->QuerySecurityPackageInfo(NTLM_PACKAGE, &pPkgInfo))) { m_gpFuncs->FreeContextBuffer(pPkgInfo); } else { hr=E_FAIL; } } if(S_OK==hr) { //To circumvent the ADsGetObject leak
hr = CoCreateInstance( __uuidof( P3Config ), NULL, CLSCTX_ALL, __uuidof( IP3Config ),reinterpret_cast<LPVOID *>( &m_gpIConfig )); }
if(S_OK==hr) { //Set the flag to be 1
InterlockedExchange(&m_glInit, 1); } else { //Cleanup
m_gpFuncs=NULL; if(NULL != m_ghLib) { FreeLibrary(m_ghLib); m_ghLib=NULL; } //Set the falg to be 0
InterlockedExchange(&m_glInit, 0); }
} else { while(1!=m_glInit) { Sleep(50); //Wait for the initialization to be done
} }
return hr; }
void CAuthServer::GlobalUninit() {
long lRet=InterlockedCompareExchange(&m_glInit, -1, 1); switch (lRet) { case 2:while(1!=m_glInit) { Sleep(50); } case 1:m_gpFuncs=NULL; if(NULL != m_ghLib) { FreeLibrary(m_ghLib); m_ghLib=NULL; } if(m_gpIConfig!=NULL) { m_gpIConfig->Release(); m_gpIConfig=NULL; } break; case 0://Nothing needed to be done
default: break; }; }
CAuthServer::CAuthServer() {
m_bInit=FALSE; m_bHaveSecContext=FALSE; m_bFirstCall=TRUE;
}
CAuthServer::~CAuthServer() { Cleanup(); }
void CAuthServer::Cleanup() { if(NULL != m_gpFuncs) {
if(m_bInit) { m_bInit=FALSE; m_bFirstCall=TRUE; m_gpFuncs->FreeCredentialHandle(&m_hCredHandle); if(m_bHaveSecContext) { m_bHaveSecContext=FALSE; m_gpFuncs->DeleteSecurityContext(&m_hSecContext); } } } else { //This should never happen!
g_EventLogger.LogEvent(LOGTYPE_ERR_CRITICAL, EVENT_POP3_UNEXPECTED_ERROR); } }
HRESULT CAuthServer::InitCredential() { HRESULT hr=S_OK; SECURITY_STATUS status; TimeStamp tsExpire; if(!m_bInit) { if(m_glInit!=1) { hr=GlobalInit(); } if(S_OK == hr ) { if(!m_bInit) { status = m_gpFuncs->AcquireCredentialsHandle( NULL, NTLM_PACKAGE, SECPKG_CRED_INBOUND, NULL, NULL, NULL, NULL, &m_hCredHandle, &tsExpire); if(SEC_E_OK != status) { hr=E_FAIL; } else { m_bInit=TRUE; } } } } return hr; }
HRESULT CAuthServer::HandShake(LPBYTE pInBuf, DWORD cbInBufSize, LPBYTE pOutBuf, PDWORD pcbOutBufSize) { HRESULT hr=S_OK; SECURITY_STATUS status; TimeStamp tsExpire; ULONG ulContextAttributes; BUFFER uuBuf; DWORD cbDecoded=0; BYTE pBuf[AUTH_BUF_SIZE]; SecBufferDesc OutBuffDesc; SecBuffer OutSecBuff; SecBufferDesc InBuffDesc; SecBuffer InSecBuff; if( (NULL == pInBuf) || (NULL == pOutBuf) || (NULL == pcbOutBufSize) ) { return E_INVALIDARG; } if(!m_bInit) { hr = InitCredential(); }
uuBuf.pBuf=pBuf; uuBuf.cLen=AUTH_BUF_SIZE; if( !uudecode((char *)pInBuf, &uuBuf, &cbDecoded)) { hr=E_FAIL; }
if( S_OK == hr ) {
OutBuffDesc.ulVersion = 0; OutBuffDesc.cBuffers = 1; OutBuffDesc.pBuffers = &OutSecBuff;
OutSecBuff.cbBuffer = *pcbOutBufSize; OutSecBuff.BufferType = SECBUFFER_TOKEN; OutSecBuff.pvBuffer = pOutBuf;
InBuffDesc.ulVersion = 0; InBuffDesc.cBuffers = 1; InBuffDesc.pBuffers = &InSecBuff;
InSecBuff.cbBuffer = cbDecoded;//cbInBufSize;
InSecBuff.BufferType = SECBUFFER_TOKEN; InSecBuff.pvBuffer = pBuf;//pInBuf;
status = m_gpFuncs->AcceptSecurityContext ( &m_hCredHandle, m_bFirstCall? NULL:&m_hSecContext, &InBuffDesc, 0, SECURITY_NETWORK_DREP, &m_hSecContext, &OutBuffDesc, &ulContextAttributes, &tsExpire ); if( !SEC_SUCCESS(status) ) { hr=E_FAIL; } else { m_bHaveSecContext=TRUE; m_bFirstCall=FALSE; }
switch(status) { case SEC_E_OK:hr=S_OK; break; case SEC_I_CONTINUE_NEEDED:hr=S_FALSE; break; case SEC_I_COMPLETE_AND_CONTINUE:hr=S_FALSE; //Continue to do the following
case SEC_I_COMPLETE_NEEDED:if(m_gpFuncs->CompleteAuthToken) { status=m_gpFuncs->CompleteAuthToken( &m_hSecContext, &OutBuffDesc); if( !(SEC_SUCCESS(status)) ) { hr=E_FAIL; } } else { hr=E_FAIL; } break; default: hr=E_FAIL; } }
if(SUCCEEDED(hr)) { uuBuf.cLen=AUTH_BUF_SIZE; if(OutSecBuff.cbBuffer > (AUTH_BUF_SIZE-5)*2/3) { //This is the case where the buffer is not big
// enough
hr=E_OUTOFMEMORY; } else { if(uuencode(pOutBuf, OutSecBuff.cbBuffer, &uuBuf)) { pOutBuf[AUTH_BUF_SIZE-1]=0; if( 0>_snprintf((char *)pOutBuf, AUTH_BUF_SIZE-1, "+ %s\r\n", (char *)(uuBuf.pBuf)) ) { hr=E_FAIL; } else { *pcbOutBufSize=strlen((char *)pOutBuf); } } else { hr=E_FAIL; } } } if(FAILED(hr)) { if(m_bHaveSecContext) { m_gpFuncs->DeleteSecurityContext(&m_hSecContext); m_bHaveSecContext=FALSE; m_bFirstCall=TRUE; } }
return hr; } HRESULT CAuthServer::GetUserName(WCHAR *wszUserName) { SecPkgContext_Names SecUserName; SECURITY_STATUS status; WCHAR *pUserName=NULL; WCHAR *pAt=NULL; VARIANT var; VariantInit(&var); HRESULT hr=S_OK; if(NULL==wszUserName) { return E_POINTER; } if(!m_bHaveSecContext) { return E_FAIL; }
status=QueryContextAttributes( &m_hSecContext, SECPKG_ATTR_NAMES, &SecUserName); if(SEC_E_OK != status) { return E_FAIL; } else { if(AUTH_AD==g_dwAuthMethod) {
var.vt=VT_BSTR; var.bstrVal=SysAllocString(SecUserName.sUserName); if(NULL == var.bstrVal) { var.vt=VT_EMPTY; hr=E_OUTOFMEMORY; } else { hr=g_pAuthMethod->Get(SZ_EMAILADDR, &var); if(SUCCEEDED(hr)) { if(wcslen(var.bstrVal) < POP3_MAX_ADDRESS_LENGTH) { wcscpy(wszUserName, var.bstrVal); } else { hr=E_FAIL; } } } } else //SAM case
{
pAt=wcschr(SecUserName.sUserName, L'\\'); if(NULL == pAt) { pUserName=SecUserName.sUserName; } else { pUserName=pAt+1; } CComPtr<IP3Config> spIConfig; CComPtr<IP3Domains> spIDomains; hr = CoCreateInstance( __uuidof( P3Config ), NULL, CLSCTX_ALL, __uuidof( IP3Config ),reinterpret_cast<LPVOID *>( &spIConfig )); if( S_OK == hr ) { if( S_OK== hr) { hr = spIConfig->get_Domains( &spIDomains ); } } if( S_OK == hr ) { BSTR bstrDomainName=NULL; CComBSTR bstrUserName(pUserName); hr = spIDomains->SearchForMailbox(bstrUserName, &bstrDomainName); if ( S_OK == hr ) { if(0> _snwprintf(wszUserName, POP3_MAX_ADDRESS_LENGTH-1, L"%s@%s", pUserName, bstrDomainName) ) { hr=E_FAIL; } wszUserName[POP3_MAX_ADDRESS_LENGTH-1]=L'\0'; SysFreeString(bstrDomainName); } } }
m_gpFuncs->FreeContextBuffer(SecUserName.sUserName); VariantClear(&var); return hr; }
}
|