Here is the c++ code for the native library NTLMAuthEx.cpp, this is compiled into a native dll NTLMAuthEx.dll
// NTLMAuthEx.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
#include "security.h"
#include "sspi.h"
#define SEC_SUCCESS(Status) ((Status) >= 0)
// structure storing the state of the authentication sequence
typedef struct _AUTH_SEQ {
BOOL _fInitialized;
CredHandle _hcred;
BOOL _fHaveCredHandle;
DWORD _cbMaxToken;
BOOL _fHaveCtxtHandle;
struct _SecHandle _hctxt;
BOOL _fUUEncodeData;
} AUTH_SEQ;
AUTH_SEQ g_authseq;
/************************************************************
* uuencode/decode functions
************************************************************/
//
// Taken from NCSA HTTP and wwwlib.
//
// NOTE: These conform to RFC1113, which is slightly different then the Unix
// uuencode and uudecode!
//
const int pr2six[256]={
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,62,64,64,64,63,
52,53,54,55,56,57,58,59,60,61,64,64,64,64,64,64,64,0,1,2,3,4,5,6,7,8,9,
10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,64,64,64,64,64,64,26,27,
28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
64,64,64,64,64,64,64,64,64,64,64,64,64
};
char six2pr[64] = {
'A','B','C','D','E','F','G','H','I','J','K','L','M',
'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
'a','b','c','d','e','f','g','h','i','j','k','l','m',
'n','o','p','q','r','s','t','u','v','w','x','y','z',
'0','1','2','3','4','5','6','7','8','9','+','/'
};
BOOL uuencode(BYTE *bufin, DWORD nbytes, BYTE *pbOutData)
{
unsigned int i;
BYTE *outptr = pbOutData;
for (i=0; i<nbytes; i += 3) {
*(outptr++) = six2pr[*bufin >> 2]; /* c1 */
*(outptr++) = six2pr[((*bufin << 4) & 060) | ((bufin[1] >> 4) & 017)]; /*c2*/
*(outptr++) = six2pr[((bufin[1] << 2) & 074) | ((bufin[2] >> 6) & 03)];/*c3*/
*(outptr++) = six2pr[bufin[2] & 077]; /* c4 */
bufin += 3;
}
/* If nbytes was not a multiple of 3, then we have encoded too
* many characters. Adjust appropriately.
*/
if(i == nbytes+1) {
/* There were only 2 bytes in that last group */
outptr[-1] = '=';
} else if(i == nbytes+2) {
/* There was only 1 byte in that last group */
outptr[-1] = '=';
outptr[-2] = '=';
}
*outptr = '\0';
return TRUE;
}
BOOL uudecode(char *bufcoded, BYTE *pbuffdecoded, DWORD *pcbDecoded)
{
int nbytesdecoded;
char *bufin = bufcoded;
BYTE *bufout;
int nprbytes;
/* Strip leading whitespace. */
while(*bufcoded==' ' || *bufcoded == '\t') bufcoded++;
/* Figure out how many characters are in the input buffer.
* If this would decode into more bytes than would fit into
* the output buffer, adjust the number of input bytes downwards.
*/
bufin = bufcoded;
while(pr2six[*(bufin++)] <= 63);
nprbytes = (int)(INT_PTR)(bufin - bufcoded - 1);
nbytesdecoded = ((nprbytes+3)/4) * 3;
bufout = pbuffdecoded;
bufin = bufcoded;
while (nprbytes > 0) {
*(bufout++) =
(unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
*(bufout++) =
(unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
*(bufout++) =
(unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
bufin += 4;
nprbytes -= 4;
}
if(nprbytes & 03) {
if(pr2six[bufin[-2]] > 63)
nbytesdecoded -= 2;
else
nbytesdecoded -= 1;
}
pbuffdecoded[nbytesdecoded] = '\0';
return TRUE;
}
BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
return TRUE;
}
extern "C" DWORD __declspec(dllexport) FAR PASCAL Initialize(LPTSTR pszUserID, LPTSTR pszPassword, LPTSTR pszDomain)
{
SECURITY_STATUS ss;
TimeStamp Lifetime;
ZeroMemory(&g_authseq, sizeof(_AUTH_SEQ));
SEC_WINNT_AUTH_IDENTITY ident = {0};
SecPkgInfo *pspkg;
ident.User = (unsigned short*)pszUserID;
ident.Password = (unsigned short*)pszPassword;
ident.Domain = (unsigned short*)pszDomain;
ss = AcquireCredentialsHandle(NULL, L"NTLM", SECPKG_CRED_OUTBOUND, NULL, &ident, NULL, NULL, &g_authseq._hcred, &Lifetime);
if (ss != STATUS_SUCCESS)
return 0;
ss = QuerySecurityPackageInfo(L"NTLM", &pspkg);
if (ss != STATUS_SUCCESS)
return 0;
g_authseq._cbMaxToken = pspkg->cbMaxToken;
FreeContextBuffer(pspkg);
// Because the the result will be uuencoded, request the buffer to be 133%
DWORD cbBufferSize = g_authseq._cbMaxToken + ((g_authseq._cbMaxToken + 3) / 3) + 4;
g_authseq._fInitialized = TRUE;
return cbBufferSize;
}
extern "C" DWORD __declspec(dllexport) FAR PASCAL Authenicate(BYTE *pbResponse, BYTE *pbBuffer, DWORD *pnBufferSize)
{
DWORD dwReturn = -1;
BYTE *pbuff = NULL;
BYTE *pBuffIn = NULL;
DWORD dwBuffInLen = 0;
SECURITY_STATUS ss;
TimeStamp Lifetime;
SecBufferDesc OutBuffDesc;
SecBuffer OutSecBuff;
SecBufferDesc InBuffDesc;
SecBuffer InSecBuff;
ULONG ContextAttributes;
PCredHandle phCredential = NULL;
PSecBufferDesc pInput = NULL;
if (!g_authseq._fInitialized)
{
goto exit;
}
ZeroMemory(pbBuffer, *pnBufferSize);
if (pbResponse)
{
dwBuffInLen = strlen((char*)pbResponse);
pBuffIn = new BYTE[dwBuffInLen];
uudecode((char*)pbResponse, pBuffIn, &dwBuffInLen);
}
pbuff = new BYTE[*pnBufferSize];
OutBuffDesc.ulVersion = 0;
OutBuffDesc.cBuffers = 1;
OutBuffDesc.pBuffers = &OutSecBuff;
OutSecBuff.cbBuffer = g_authseq._cbMaxToken;
OutSecBuff.BufferType = SECBUFFER_TOKEN;
OutSecBuff.pvBuffer = pbuff;
if (pBuffIn)
{
InBuffDesc.ulVersion = 0;
InBuffDesc.cBuffers = 1;
InBuffDesc.pBuffers = &InSecBuff;
InSecBuff.cbBuffer = dwBuffInLen;
InSecBuff.BufferType = SECBUFFER_TOKEN;
InSecBuff.pvBuffer = pBuffIn;
phCredential = &g_authseq._hctxt;
pInput = &InBuffDesc;
}
ss = InitializeSecurityContext(
&g_authseq._hcred, phCredential, L"InetSvcs", 0, 0, SECURITY_NATIVE_DREP, pInput, 0, &g_authseq._hctxt,
&OutBuffDesc, &ContextAttributes, &Lifetime);
if (!SEC_SUCCESS(ss))
{
dwReturn = GetLastError();
goto exit;
}
uuencode((BYTE*)OutSecBuff.pvBuffer, OutSecBuff.cbBuffer, pbBuffer);
*pnBufferSize = strlen((char*)pbBuffer);
dwReturn = 0;
exit:
if (pbuff)
delete [] pbuff;
if (pBuffIn)
delete [] pBuffIn;
return dwReturn;
}