Hi,@Greg_N_Huntsville Could you please check if the following sample is helpful to you?
CSampleCredential.cpp:
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) 2006 Microsoft Corporation. All rights reserved.
//
//
#ifndef WIN32_NO_STATUS
#include <ntstatus.h>
#define WIN32_NO_STATUS
#endif
#include <unknwn.h>
//#include <tchar.h>
#include "CSampleCredential.h"
#include "guid.h"
#include <wincred.h>
/*
#define UNICODE
#define _UNICODE
#define SECURITY_WIN32
#include <windows.h>
#include <credentialprovider.h>
#include <ntsecapi.h>
#include <tchar.h>
#include <security.h>
#include <intsafe.h>
#include <wincrypt.h>
#include <stdio.h>
*/
void mylog (CHAR * lpFmt, ...)
{
va_list arglist;
CHAR szTemp [1024];
HANDLE hLogFile;
DWORD dwNumberOfCharactersWritten=0,dwNumberOfBytesWritten=0;
SYSTEMTIME systemtime;
GetLocalTime (&systemtime);
dwNumberOfCharactersWritten = wsprintfA (szTemp, "[PID: %u](%02u/%02u/%02u %02u:%02u:%02u:%03u) - ", GetCurrentProcessId(), systemtime.wMonth, systemtime.wDay, systemtime.wYear, systemtime.wHour, systemtime.wMinute, systemtime.wSecond, systemtime.wMilliseconds);
va_start(arglist, lpFmt);
dwNumberOfCharactersWritten += wvsprintfA (szTemp + dwNumberOfCharactersWritten, lpFmt, arglist);
va_end(arglist);
dwNumberOfCharactersWritten += wsprintfA (szTemp + dwNumberOfCharactersWritten, "\r\n");
WriteConsoleA (GetStdHandle (STD_OUTPUT_HANDLE), szTemp, lstrlenA (szTemp), &dwNumberOfCharactersWritten, 0);
hLogFile = CreateFileA ("c:\\logfile.txt", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
SetFilePointer (hLogFile, 0, 0, FILE_END);
WriteFile (hLogFile, szTemp, dwNumberOfCharactersWritten * sizeof(CHAR), &dwNumberOfBytesWritten, NULL);
FlushFileBuffers (hLogFile);
CloseHandle (hLogFile);
} // log
#define ALIGN_LPVOID sizeof(LPVOID)
#define ROUND_UP_COUNT(Count,Pow2) \
( ((Count)+(Pow2)-1) & (~(((LONG)(Pow2))-1)) )
typedef enum _KERB_SMARTCARD_CSP_INFO_TYPE {
LogonInfo2 = 1,
KERB_SMARTCARD_CSP_INFO_MAX_TYPE = 10,
} KERB_SMARTCARD_CSP_INFO_TYPE, *PKERB_SMARTCARD_CSP_INFO_TYPE;
/*
typedef enum _KERB_LOGON_SUBMIT_TYPE {
KerbInteractiveLogon = 2,
KerbSmartCardLogon = 6,
KerbWorkstationUnlockLogon = 7,
KerbSmartCardUnlockLogon = 8,
KerbProxyLogon = 9,
KerbTicketLogon = 10,
KerbTicketUnlockLogon = 11,
KerbS4ULogon = 12,
KerbCertificateLogon = 13,
KerbCertificateS4ULogon = 14,
KerbCertificateUnlockLogon = 15,
} KERB_LOGON_SUBMIT_TYPE, *PKERB_LOGON_SUBMIT_TYPE;
*/
typedef struct _KERB_SMARTCARD_CSP_INFO {
DWORD dwCspInfoLen;
DWORD MessageType;
union {
PVOID ContextInformation; // 4 bytes.
ULONG64 SpaceHolderForWow64; // 8 bytes.
//LONG64 SpaceHolderForWow64; // <-- adding this back goes from 36 to 48 bytes for the structure.
};
DWORD flags;
DWORD KeySpec;
ULONG nCardNameOffset;
ULONG nReaderNameOffset;
ULONG nContainerNameOffset;
ULONG nCSPNameOffset;
WCHAR bBuffer[1]; // TCHAR=WCHAR= 2bytes, 4 total for this array.
} KERB_SMARTCARD_CSP_INFO, *PKERB_SMARTCARD_CSP_INFO;
/*
typedef struct _KERB_CERTIFICATE_LOGON {
KERB_LOGON_SUBMIT_TYPE MessageType; // KerbCertificateLogon
LSA_UNICODE_STRING DomainName; // OPTIONAL, if supplied, used to locate the account forest
LSA_UNICODE_STRING UserName; // OPTIONAL, if supplied, used to locate the account
LSA_UNICODE_STRING Pin;
ULONG Flags; // additional flags
ULONG CspDataLength;
PUCHAR CspData; // contains the smartcard CSP data
} KERB_CERTIFICATE_LOGON, *PKERB_CERTIFICATE_LOGON;
typedef struct _KERB_CERTIFICATE_UNLOCK_LOGON {
KERB_CERTIFICATE_LOGON Logon;
LUID LogonId;
} KERB_CERTIFICATE_UNLOCK_LOGON, *PKERB_CERTIFICATE_UNLOCK_LOGON;
*/
//
// This function packs the string pszSourceString in pszDestinationString
// for use with LSA functions including LsaLookupAuthenticationPackage.
//
/*
HRESULT LsaInitString(PSTRING pszDestinationString, PCSTR pszSourceString)
{
USHORT usLength;
HRESULT hr = SizeTToUShort(strlen(pszSourceString), &usLength);
if (SUCCEEDED(hr))
{
pszDestinationString->Buffer = (PCHAR)pszSourceString;
pszDestinationString->Length = usLength;
pszDestinationString->MaximumLength = pszDestinationString->Length+1;
hr = S_OK;
}
return hr;
}
*/
//
// Retrieves the 'negotiate' AuthPackage from the LSA. In this case, Kerberos
// For more information on auth packages see this msdn page:
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/msv1_0_lm20_logon.asp
//
/*
HRESULT RetrieveNegotiateAuthPackage(ULONG * pulAuthPackage)
{
HRESULT hr;
HANDLE hLsa;
NTSTATUS status = LsaConnectUntrusted(&hLsa);
if (SUCCEEDED(HRESULT_FROM_NT(status)))
{
ULONG ulAuthPackage;
LSA_STRING lsaszKerberosName;
LsaInitString(&lsaszKerberosName, NEGOSSP_NAME_A);
status = LsaLookupAuthenticationPackage(hLsa, &lsaszKerberosName, &ulAuthPackage);
if (SUCCEEDED(HRESULT_FROM_NT(status)))
{
*pulAuthPackage = ulAuthPackage;
hr = S_OK;
}
else
{
hr = HRESULT_FROM_NT(status);
}
LsaDeregisterLogonProcess(hLsa);
}
else
{
hr= HRESULT_FROM_NT(status);
}
return hr;
}
*/
void hexlog(CHAR * lpFmt, ...)
{
va_list arglist;
CHAR szTemp [1024];
HANDLE hLogFile;
DWORD dwNumberOfCharactersWritten=0,dwNumberOfBytesWritten=0;
//SYSTEMTIME systemtime;
va_start(arglist, lpFmt);
dwNumberOfCharactersWritten += wvsprintfA (szTemp + dwNumberOfCharactersWritten, lpFmt, arglist);
va_end(arglist);
hLogFile = CreateFileA ("c:\\logfile.txt", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
SetFilePointer (hLogFile, 0, 0, FILE_END);
WriteFile (hLogFile, szTemp, dwNumberOfCharactersWritten * sizeof(CHAR), &dwNumberOfBytesWritten, NULL);
FlushFileBuffers (hLogFile);
CloseHandle (hLogFile);
} // log
/*
void hexlog(CHAR * lpFmt, ...)
{
va_list arglist;
CHAR szTemp [1024];
DWORD dwNumberOfCharactersWritten=0,dwNumberOfBytesWritten=0;
va_start(arglist, lpFmt);
dwNumberOfCharactersWritten += wvsprintfA (szTemp + dwNumberOfCharactersWritten, lpFmt, arglist);
va_end(arglist);
printf("%s", szTemp);
} // log
*/
/*
void hexlog(CHAR * lpFmt, ...)
{
} // log
*/
void HexDump (BYTE * pBuf, DWORD dwLen)
{
DWORD i, u, v;
BYTE * p;
hexlog("\r\n");
p = pBuf;
i = u = v = 0;
for (u=0; u<(dwLen/16); u++)
{
for (v=0; v<16; v++)
{
hexlog("%.2x ", p[i]);
i++;
}
hexlog(" ");
i -= 16;
for (v=0; v<16; v++)
{
if ((p[i] > 32) && (p[i] < 127))
hexlog("%c", p[i]);
else
hexlog(".");
i++;
}
hexlog("\r\n");
}
for (u=0; u<(dwLen%16); u++)
hexlog("%.2x ", p[i+u]);
for (u=0; u<(((16-(dwLen%16))*3)+3); u++)
hexlog(" ");
for (u=0; u<(dwLen%16); u++)
if ((p[i+u] > 32) && (p[i+u] < 127))
hexlog("%c", p[i+u]);
else
hexlog(".");
hexlog("\r\n");
hexlog("\r\n%u total bytes.\r\n\r\n", dwLen);
} // HexDump
//STDMETHODIMP
HRESULT EncryptPin(__in LPWSTR rgwszPin,
__deref_out LPWSTR * ppwszEncryptedPin,
__out DWORD *pcbPin)
{
CRED_PROTECTION_TYPE ProtectionType;
BOOLEAN bEnc = TRUE;
DWORD dwSts = ERROR_SUCCESS;
HRESULT hr = S_OK;
DWORD cchPin = 0;
DWORD cchEncPin = 0;
DWORD cbPin = 0;
DWORD dwEncLen = 0;
LPWSTR pwszEncPin = NULL;
hr = ULongAdd(lstrlenW(rgwszPin), 1, &cchPin);
if (FAILED(hr))
{
return hr;
}
if(!CredIsProtectedW(rgwszPin,
&ProtectionType
))
{
hr = HRESULT_FROM_WIN32(GetLastError());
return hr;
}
if(CredUnprotected != ProtectionType)
{
bEnc = FALSE;
}
if(bEnc)
{
if(!CredProtectW(FALSE,
rgwszPin,
cchPin,
NULL,
&cchEncPin,
NULL))
{
dwSts = GetLastError();
if (ERROR_INSUFFICIENT_BUFFER == dwSts)
{
hr = ULongAdd(cchEncPin, 1, &cbPin);
if (SUCCEEDED(hr))
{
hr = ULongMult(cbPin, sizeof(WCHAR), &cbPin);
}
if (SUCCEEDED(hr))
{
pwszEncPin = (WCHAR *)malloc(cbPin);
}
if (SUCCEEDED(hr))
{
cchEncPin = cbPin /sizeof(WCHAR);
if (!CredProtectW(FALSE,
rgwszPin,
cchPin,
pwszEncPin,
&cchEncPin,
NULL))
{
hr = HRESULT_FROM_WIN32(GetLastError());
mylog("CredProtectW failed: %u\r\n", GetLastError());
}
else
mylog("CredProtectW succeeded.\r\n");
}
}
else
{
hr = HRESULT_FROM_WIN32(dwSts);
}
}else
{
// We expect this call to fail
hr = E_UNEXPECTED;
}
if (SUCCEEDED(hr))
{
dwEncLen = cchEncPin * sizeof(WCHAR);
}
}
/*
else
{
hr = ULongMult(cchPin, sizeof(WCHAR), &cbPin);
if (SUCCEEDED(hr))
{
pwszEncPin = (WCHAR *)malloc(cbPin);
}
if (SUCCEEDED(hr))
{
memcpy(pwszEncPin,rgwszPin,cbPin);
// Explicit lack of NULL
dwEncLen = cbPin - sizeof(WCHAR);
}
}
*/
//if (SUCCEEDED(hr))
//{
*pcbPin = dwEncLen;
*ppwszEncryptedPin = pwszEncPin;
pwszEncPin = NULL;
//}
//if (pwszEncPin)
// free(pwszEncPin);
//return hr;
return S_OK;
}
HRESULT DoCredSerialization(
__out CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE* pcpgsr,
__out CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcs,
PWSTR pwszPin, PCWSTR pwszCardName, PCWSTR pwszReaderName, PCWSTR pwszContainerName, PCWSTR pwszProviderName
)
{
HRESULT hr;
//ISmartcardError *psce = NULL;
//PCWSTR pwszCardName = L"Axalto Cryptoflex .NET"; //_psrd->GetCardName(); 22chars=23*2=46bytes
//PCWSTR pwszReaderName = L"Gemplus USB Smart Card Reader 0"; //_psrd->GetReaderName(); 31chars=32*2=64bytes
//PCWSTR pwszContainerName = L"le-MSSmartcardUser-1c926350-2652--33341"; //_psrcd->GetContainer(); 39chars=40*2=80bytes
//PCWSTR pwszProviderName = L"Microsoft Base Smart Card Crypto Provider"; //_psrd->GetProviderName(); 41chars=42*2=84bytes
LPWSTR pwszEncryptedPin = NULL;
DWORD dwEncLen = 0;
DWORD dwLogonInfoLen = 0;
/*
BYTE bPin[] =
{0x40, 0x00, 0x40, 0x00, 0x44, 0x00, 0x07, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x67, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x6e, 0x00, 0x50, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x52, 0x00, 0x45, 0x00, 0x45, 0x00, 0x79, 0x00, 0x43, 0x00, 0x69, 0x00, 0x49, 0x00, 0x71, 0x00, 0x44, 0x00, 0x38, 0x00, 0x51, 0x00, 0x4a, 0x00, 0x6d, 0x00, 0x53, 0x00, 0x52, 0x00, 0x78, 0x00, 0x73, 0x00, 0x61, 0x00, 0x6a, 0x00, 0x79, 0x00, 0x51, 0x00, 0x37, 0x00, 0x52, 0x00, 0x39, 0x00, 0x44, 0x00, 0x4e, 0x00, 0x70, 0x00, 0x4f, 0x00, 0x43, 0x00, 0x35, 0x00, 0x32, 0x00, 0x45, 0x00, 0x00, 0x00}; // 116 bytes.
*/
hr = EncryptPin(pwszPin, &pwszEncryptedPin, &dwEncLen);
if (SUCCEEDED(hr))
{
mylog("EncryptPin succeeded.\r\n");
HexDump((BYTE *)pwszEncryptedPin, dwEncLen);
}
else
{
mylog("EncryptPin failed.\r\n");
return hr;
}
// pin value: 40 00 40 00 44 00 07 00 08 00 0c 00 0a 00 0d 00 67 00 41 00 41 00 41 00 41 00 41 00 6e 00 50 00 41 00 41 00 41 00 41 00 41 00 41 00 41 00 41 00 41 00 52 00 45 00 45 00 79 00 43 00 69 00 49 00 71 00 44 00 38 00 51 00 4a 00 6d 00 53 00 52 00 78 00 73 00 61 00 6a 00 79 00 51 00 37 00 52 00 39 00 44 00 4e 00 70 00 4f 00 43 00 35 00 32 00 45 00 00 00
/*
0d 00 00 00 00 00 00 00 28 00 00 00 00 00 00 00 ........(.......
28 00 00 00 74 00 74 00 28 00 00 00 00 00 00 00 (...t.t.(.......
40 01 00 00 9c 00 00 00 40 00 40 00 44 00 07 00 @.......@.@.D...
08 00 0c 00 0a 00 0d 00 67 00 41 00 41 00 41 00 ........g.A.A.A.
41 00 41 00 6e 00 50 00 41 00 41 00 41 00 41 00 A.A.n.P.A.A.A.A.
41 00 41 00 41 00 41 00 77 00 74 00 75 00 4a 00 A.A.A.A.w.t.u.J.
72 00 4a 00 62 00 79 00 74 00 47 00 6b 00 45 00 r.J.b.y.t.G.k.E.
62 00 52 00 64 00 49 00 6d 00 65 00 23 00 46 00 b.R.d.I.m.e.#.F.
43 00 46 00 73 00 64 00 51 00 72 00 6c 00 79 00 C.F.s.d.Q.r.l.y.
4d 00 4b 00 74 00 76 00 46 00 00 00 40 01 00 00 M.K.t.v.F...@...
01 00 00 00 00 00 00 00 a8 b1 f6 00 15 00 01 00 ................
01 00 00 00 00 00 00 00 17 00 00 00 3a 00 00 00 ............:...
62 00 00 00 41 00 78 00 61 00 6c 00 74 00 6f 00 b...A.x.a.l.t.o.
20 00 43 00 72 00 79 00 70 00 74 00 6f 00 66 00 ..C.r.y.p.t.o.f.
6c 00 65 00 78 00 20 00 2e 00 4e 00 45 00 54 00 l.e.x.....N.E.T.
00 00 4f 00 4d 00 4e 00 49 00 4b 00 45 00 59 00 ..O.M.N.I.K.E.Y.
20 00 41 00 47 00 20 00 53 00 6d 00 61 00 72 00 ..A.G...S.m.a.r.
74 00 20 00 43 00 61 00 72 00 64 00 20 00 52 00 t...C.a.r.d...R.
65 00 61 00 64 00 65 00 72 00 20 00 55 00 53 00 e.a.d.e.r...U.S.
42 00 20 00 30 00 00 00 6c 00 65 00 2d 00 4d 00 B...0...l.e.-.M.
53 00 53 00 6d 00 61 00 72 00 74 00 63 00 61 00 S.S.m.a.r.t.c.a.
72 00 64 00 55 00 73 00 65 00 72 00 2d 00 37 00 r.d.U.s.e.r.-.7.
32 00 36 00 37 00 32 00 62 00 39 00 62 00 2d 00 2.6.7.2.b.9.b.-.
30 00 30 00 61 00 64 00 2d 00 2d 00 33 00 36 00 0.0.a.d.-.-.3.6.
37 00 33 00 34 00 00 00 4d 00 69 00 63 00 72 00 7.3.4...M.i.c.r.
6f 00 73 00 6f 00 66 00 74 00 20 00 42 00 61 00 o.s.o.f.t...B.a.
73 00 65 00 20 00 53 00 6d 00 61 00 72 00 74 00 s.e...S.m.a.r.t.
20 00 43 00 61 00 72 00 64 00 20 00 43 00 72 00 ..C.a.r.d...C.r.
79 00 70 00 74 00 6f 00 20 00 50 00 72 00 6f 00 y.p.t.o...P.r.o.
76 00 69 00 64 00 65 00 72 00 00 00 v.i.d.e.r...
476 total bytes.
[PID: 4396]
*/
// size of KERB_CERTIFICATE_UNLOCK_LOGON or KERB_CERTIFICATE_LOGON
//const size_t cbKERB_CERTIFICATE_UNLOCK_LOGON = sizeof(KERB_CERTIFICATE_UNLOCK_LOGON);
const size_t cbKERB_CERTIFICATE_LOGON = sizeof(KERB_CERTIFICATE_LOGON);
PCWSTR pwszDomainHint = NULL;
PCWSTR pwszUserNameHint = NULL;
size_t cbDomainHint = 0;
size_t cbUserNameHint = 0; //wcslen(_rgwszUserNameHint) * sizeof(WCHAR); // mjs
// size of KERB_SMARTCARD_CSP_INFO
//const size_t cbKerbSCCSPInfo = offsetof(KERB_SMARTCARD_CSP_INFO, bBuffer);
const size_t cbKerbSCCSPInfo = sizeof(KERB_SMARTCARD_CSP_INFO) - (sizeof(WCHAR)*2);
size_t cbCardName = (wcslen(pwszCardName) + 1) * sizeof(WCHAR);
size_t cbReaderName = (wcslen(pwszReaderName) + 1) * sizeof(WCHAR);
size_t cbContainerName = (wcslen(pwszContainerName) + 1) * sizeof(WCHAR);
size_t cbProviderName = (wcslen(pwszProviderName) + 1) * sizeof(WCHAR);
mylog("%u %u %u %u %u\n", sizeof(KERB_SMARTCARD_CSP_INFO) /*cbKerbSCCSPInfo*/, cbCardName, cbReaderName, cbContainerName, cbProviderName);
size_t cbCspDataLength = 0x140; //cbKerbSCCSPInfo + cbCardName + cbReaderName + cbContainerName + cbProviderName;
mylog("%u %u %u %u %u\n", cbKerbSCCSPInfo, cbCardName, cbReaderName, cbContainerName, cbProviderName);
size_t cb = ROUND_UP_COUNT(cbKERB_CERTIFICATE_LOGON, ALIGN_LPVOID) +
ROUND_UP_COUNT(dwEncLen, ALIGN_LPVOID) +
ROUND_UP_COUNT(cbDomainHint, ALIGN_LPVOID) +
ROUND_UP_COUNT(cbUserNameHint, ALIGN_LPVOID) +
cbCspDataLength;
BYTE* rgbBase;
rgbBase = (BYTE *)CoTaskMemAlloc(cb); //(BYTE *)malloc(cb);
//KERB_INTERACTIVE_UNLOCK_LOGON* pkiulOut = (KERB_INTERACTIVE_UNLOCK_LOGON*)CoTaskMemAlloc(cb);
memset(rgbBase, 0, cb);
mylog("cb: %u\n", cb);
//if (SUCCEEDED(hr))
//{
// mylog("EncryptPin succeeded.\r\n");
memset(rgbBase, 0, cb - cbCspDataLength);
ULONG NegoPackageId;
hr = RetrieveNegotiateAuthPackage(&NegoPackageId);
if (SUCCEEDED(hr))
{
mylog("RetrieveNegotiateAuthPackage succeeded.\r\n");
BYTE* rgb = rgbBase;
KERB_CERTIFICATE_LOGON* pkscl = reinterpret_cast<KERB_CERTIFICATE_LOGON*>(rgb);
pkscl->Flags = 0;
pkscl->MessageType = (KERB_LOGON_SUBMIT_TYPE)13; //KerbCertificateLogon = 13
rgb += ROUND_UP_COUNT(cbKERB_CERTIFICATE_LOGON, ALIGN_LPVOID);
pkscl->DomainName.Length = (USHORT)cbDomainHint;
pkscl->DomainName.MaximumLength = (USHORT)cbDomainHint;
pkscl->DomainName.Buffer = (PWSTR)(rgb - rgbBase); // offset relative to rgbBase (for serialization)
CopyMemory(rgb, pwszDomainHint, cbDomainHint);
rgb += ROUND_UP_COUNT(cbDomainHint,ALIGN_LPVOID);
pkscl->UserName.Length = (USHORT)cbUserNameHint;
pkscl->UserName.MaximumLength = (USHORT)cbUserNameHint;
pkscl->UserName.Buffer = (PWSTR)(rgb - rgbBase); // offset relative to rgbBase (for serialization)
CopyMemory(rgb, pwszUserNameHint, cbUserNameHint);
rgb += ROUND_UP_COUNT(cbUserNameHint, ALIGN_LPVOID);
pkscl->Pin.Length = (USHORT)dwEncLen;
pkscl->Pin.MaximumLength = (USHORT)dwEncLen;
pkscl->Pin.Buffer = (PWSTR)(rgb - rgbBase); // offset relative to rgbBase (for serialization)
CopyMemory(rgb, pwszEncryptedPin, dwEncLen);
rgb += ROUND_UP_COUNT(dwEncLen, ALIGN_LPVOID);
pkscl->CspDataLength = (ULONG)cbCspDataLength;
pkscl->CspData = (PUCHAR)(rgb - rgbBase); // offset relative to rgbBase (for serialization)
dwLogonInfoLen = pkscl->CspDataLength;
KERB_SMARTCARD_CSP_INFO* pli = reinterpret_cast<KERB_SMARTCARD_CSP_INFO*>(rgb);
//pli->dwLogonInfoLen = dwLogonInfoLen;
pli->dwCspInfoLen = dwLogonInfoLen;
pli->MessageType = LogonInfo2;
pli->flags = 0;
pli->KeySpec = AT_KEYEXCHANGE; //_psrcd->GetKeySpec();
pli->nCardNameOffset = 0;
pli->nReaderNameOffset = pli->nCardNameOffset + (ULONG)(cbCardName / sizeof(WCHAR));
pli->nContainerNameOffset = pli->nReaderNameOffset + (ULONG)(cbReaderName / sizeof(WCHAR));
pli->nCSPNameOffset = pli->nContainerNameOffset + (ULONG)(cbContainerName / sizeof(WCHAR));
CopyMemory(&pli->bBuffer[pli->nCardNameOffset], pwszCardName, cbCardName);
CopyMemory(&pli->bBuffer[pli->nReaderNameOffset], pwszReaderName, cbReaderName);
CopyMemory(&pli->bBuffer[pli->nContainerNameOffset], pwszContainerName, cbContainerName);
CopyMemory(&pli->bBuffer[pli->nCSPNameOffset], pwszProviderName, cbProviderName);
rgb += dwLogonInfoLen;
pcpcs->ulAuthenticationPackage = NegoPackageId;
pcpcs->clsidCredentialProvider = CLSID_SmartcardCredentialProvider;
pcpcs->cbSerialization = (ULONG)cb;
pcpcs->rgbSerialization = rgbBase;
//if (SUCCEEDED(hr))
//{
*pcpgsr = CPGSR_RETURN_CREDENTIAL_FINISHED;
//}
}
else
mylog("RetrieveNegotiateAuthPackage failed.\r\n");
//}
//Ret:
//if (pwszEncryptedPin)
// free(pwszEncryptedPin);
return hr;
}
// CSampleCredential ////////////////////////////////////////////////////////
CSampleCredential::CSampleCredential():
_cRef(1),
_pCredProvCredentialEvents(NULL)
{
DllAddRef();
ZeroMemory(_rgCredProvFieldDescriptors, sizeof(_rgCredProvFieldDescriptors));
ZeroMemory(_rgFieldStatePairs, sizeof(_rgFieldStatePairs));
ZeroMemory(_rgFieldStrings, sizeof(_rgFieldStrings));
}
CSampleCredential::~CSampleCredential()
{
if (_rgFieldStrings[SFI_PASSWORD])
{
// CoTaskMemFree (below) deals with NULL, but StringCchLength does not.
size_t lenPassword;
HRESULT hr = StringCchLengthW(_rgFieldStrings[SFI_PASSWORD], 128, &(lenPassword));
if (SUCCEEDED(hr))
{
SecureZeroMemory(_rgFieldStrings[SFI_PASSWORD], lenPassword * sizeof(*_rgFieldStrings[SFI_PASSWORD]));
}
else
{
// TODO: Determine how to handle count error here.
}
}
for (int i = 0; i < ARRAYSIZE(_rgFieldStrings); i++)
{
CoTaskMemFree(_rgFieldStrings[i]);
CoTaskMemFree(_rgCredProvFieldDescriptors[i].pszLabel);
}
DllRelease();
}
// Initializes one credential with the field information passed in.
// Set the value of the SFI_USERNAME field to pwzUsername.
// Optionally takes a password for the SetSerialization case.
HRESULT CSampleCredential::Initialize(
CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus,
const CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR* rgcpfd,
const FIELD_STATE_PAIR* rgfsp,
PCWSTR pwzUsername,
PCWSTR pwzPassword
)
{
HRESULT hr = S_OK;
_cpus = cpus;
// Copy the field descriptors for each field. This is useful if you want to vary the
// field descriptors based on what Usage scenario the credential was created for.
for (DWORD i = 0; SUCCEEDED(hr) && i < ARRAYSIZE(_rgCredProvFieldDescriptors); i++)
{
_rgFieldStatePairs[i] = rgfsp[i];
hr = FieldDescriptorCopy(rgcpfd[i], &_rgCredProvFieldDescriptors[i]);
}
// Initialize the String values of all the fields.
if (SUCCEEDED(hr))
{
hr = SHStrDupW(pwzUsername, &_rgFieldStrings[SFI_USERNAME]);
}
if (SUCCEEDED(hr))
{
hr = SHStrDupW(pwzPassword ? pwzPassword : L"", &_rgFieldStrings[SFI_PASSWORD]);
}
if (SUCCEEDED(hr))
{
hr = SHStrDupW(L"Submit", &_rgFieldStrings[SFI_SUBMIT_BUTTON]);
}
return S_OK;
}
// LogonUI calls this in order to give us a callback in case we need to notify it of anything.
HRESULT CSampleCredential::Advise(
ICredentialProviderCredentialEvents* pcpce
)
{
if (_pCredProvCredentialEvents != NULL)
{
_pCredProvCredentialEvents->Release();
}
_pCredProvCredentialEvents = pcpce;
_pCredProvCredentialEvents->AddRef();
return S_OK;
}
// LogonUI calls this to tell us to release the callback.
HRESULT CSampleCredential::UnAdvise()
{
if (_pCredProvCredentialEvents)
{
_pCredProvCredentialEvents->Release();
}
_pCredProvCredentialEvents = NULL;
return S_OK;
}
// LogonUI calls this function when our tile is selected (zoomed).
// If you simply want fields to show/hide based on the selected state,
// there's no need to do anything here - you can set that up in the
// field definitions. But if you want to do something
// more complicated, like change the contents of a field when the tile is
// selected, you would do it here.
HRESULT CSampleCredential::SetSelected(BOOL* pbAutoLogon)
{
*pbAutoLogon = FALSE;
return S_OK;
}
// Similarly to SetSelected, LogonUI calls this when your tile was selected
// and now no longer is. The most common thing to do here (which we do below)
// is to clear out the password field.
HRESULT CSampleCredential::SetDeselected()
{
HRESULT hr = S_OK;
if (_rgFieldStrings[SFI_PASSWORD])
{
// CoTaskMemFree (below) deals with NULL, but StringCchLength does not.
size_t lenPassword;
hr = StringCchLengthW(_rgFieldStrings[SFI_PASSWORD], 128, &(lenPassword));
if (SUCCEEDED(hr))
{
SecureZeroMemory(_rgFieldStrings[SFI_PASSWORD], lenPassword * sizeof(*_rgFieldStrings[SFI_PASSWORD]));
CoTaskMemFree(_rgFieldStrings[SFI_PASSWORD]);
hr = SHStrDupW(L"", &_rgFieldStrings[SFI_PASSWORD]);
}
if (SUCCEEDED(hr) && _pCredProvCredentialEvents)
{
_pCredProvCredentialEvents->SetFieldString(this, SFI_PASSWORD, _rgFieldStrings[SFI_PASSWORD]);
}
}
return hr;
}
// Gets info for a particular field of a tile. Called by logonUI to get information to
// display the tile.
HRESULT CSampleCredential::GetFieldState(
DWORD dwFieldID,
CREDENTIAL_PROVIDER_FIELD_STATE* pcpfs,
CREDENTIAL_PROVIDER_FIELD_INTERACTIVE_STATE* pcpfis
)
{
HRESULT hr;
// Validate paramters.
if ((dwFieldID < ARRAYSIZE(_rgFieldStatePairs)) && pcpfs && pcpfis)
{
*pcpfs = _rgFieldStatePairs[dwFieldID].cpfs;
*pcpfis = _rgFieldStatePairs[dwFieldID].cpfis;
hr = S_OK;
}
else
{
hr = E_INVALIDARG;
}
return hr;
}
// Sets ppwsz to the string value of the field at the index dwFieldID.
HRESULT CSampleCredential::GetStringValue(
DWORD dwFieldID,
PWSTR* ppwsz
)
{
HRESULT hr;
// Check to make sure dwFieldID is a legitimate index.
if (dwFieldID < ARRAYSIZE(_rgCredProvFieldDescriptors) && ppwsz)
{
// Make a copy of the string and return that. The caller
// is responsible for freeing it.
hr = SHStrDupW(_rgFieldStrings[dwFieldID], ppwsz);
}
else
{
hr = E_INVALIDARG;
}
return hr;
}
// Gets the image to show in the user tile.
HRESULT CSampleCredential::GetBitmapValue(
DWORD dwFieldID,
HBITMAP* phbmp
)
{
HRESULT hr;
if ((SFI_TILEIMAGE == dwFieldID) && phbmp)
{
HBITMAP hbmp = LoadBitmap(HINST_THISDLL, MAKEINTRESOURCE(IDB_TILE_IMAGE));
if (hbmp != NULL)
{
hr = S_OK;
*phbmp = hbmp;
}
else
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
}
else
{
hr = E_INVALIDARG;
}
return hr;
}
// Sets pdwAdjacentTo to the index of the field the submit button should be
// adjacent to. We recommend that the submit button is placed next to the last
// field which the user is required to enter information in. Optional fields
// should be below the submit button.
HRESULT CSampleCredential::GetSubmitButtonValue(
DWORD dwFieldID,
DWORD* pdwAdjacentTo
)
{
HRESULT hr;
// Validate parameters.
if ((SFI_SUBMIT_BUTTON == dwFieldID) && pdwAdjacentTo)
{
// pdwAdjacentTo is a pointer to the fieldID you want the submit button to appear next to.
*pdwAdjacentTo = SFI_PASSWORD;
hr = S_OK;
}
else
{
hr = E_INVALIDARG;
}
return hr;
}
// Sets the value of a field which can accept a string as a value.
// This is called on each keystroke when a user types into an e