├── RFIDCred ├── RFIDCred │ ├── resource.h │ ├── guid.cpp │ ├── Register.reg │ ├── resources.aps │ ├── tileimage.bmp │ ├── Unregister.reg │ ├── guid.h │ ├── resources.rc │ ├── RFIDCred.def │ ├── Dll.h │ ├── helpers.h │ ├── common.h │ ├── RFIDCred.filters │ ├── CSampleProvider.h │ ├── Dll.cpp │ ├── CSampleCredential.h │ ├── RFIDCred.vcproj │ ├── RFIDCred.vcxproj │ ├── csamplecredential.cpp │ ├── helpers.cpp │ └── CSampleProvider.cpp ├── install │ ├── Register.reg │ ├── Unregister.reg │ └── install.bat └── RFIDCred.sln ├── AuthGen ├── AuthGen │ ├── stdafx.cpp │ ├── targetver.h │ ├── stdafx.h │ ├── AuthGen.vcxproj.filters │ ├── AuthGen.cpp │ └── AuthGen.vcxproj └── AuthGen.sln └── README.md /RFIDCred/RFIDCred/resource.h: -------------------------------------------------------------------------------- 1 | #define IDB_TILE_IMAGE 101 2 | -------------------------------------------------------------------------------- /RFIDCred/RFIDCred/guid.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "guid.h" -------------------------------------------------------------------------------- /RFIDCred/install/Register.reg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeandsec/RFIDCred/HEAD/RFIDCred/install/Register.reg -------------------------------------------------------------------------------- /RFIDCred/RFIDCred/Register.reg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeandsec/RFIDCred/HEAD/RFIDCred/RFIDCred/Register.reg -------------------------------------------------------------------------------- /RFIDCred/RFIDCred/resources.aps: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeandsec/RFIDCred/HEAD/RFIDCred/RFIDCred/resources.aps -------------------------------------------------------------------------------- /RFIDCred/RFIDCred/tileimage.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeandsec/RFIDCred/HEAD/RFIDCred/RFIDCred/tileimage.bmp -------------------------------------------------------------------------------- /RFIDCred/install/Unregister.reg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeandsec/RFIDCred/HEAD/RFIDCred/install/Unregister.reg -------------------------------------------------------------------------------- /RFIDCred/RFIDCred/Unregister.reg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeandsec/RFIDCred/HEAD/RFIDCred/RFIDCred/Unregister.reg -------------------------------------------------------------------------------- /RFIDCred/RFIDCred/guid.h: -------------------------------------------------------------------------------- 1 | DEFINE_GUID(CLSID_CSampleProvider, 0x781a7b48, 0x79a7, 0x4fcf, 0x92, 0xcc, 0xa6, 0x97, 0x71, 0x71, 0xf1, 0xa8); 2 | -------------------------------------------------------------------------------- /RFIDCred/RFIDCred/resources.rc: -------------------------------------------------------------------------------- 1 | #include "Resource.h" 2 | 3 | // Bitmaps: 4 | IDB_TILE_IMAGE BITMAP DISCARDABLE "tileimage.bmp" 5 | END 6 | 7 | -------------------------------------------------------------------------------- /RFIDCred/install/install.bat: -------------------------------------------------------------------------------- 1 | copy /Y "C:\Users\Administrator\Desktop\SampleCredUICredentialProvider\Debug\RFIDCred.dll" C:\Windows\System32\RFIDCred.dll 2 | regedit /s register.reg -------------------------------------------------------------------------------- /RFIDCred/RFIDCred/RFIDCred.def: -------------------------------------------------------------------------------- 1 | LIBRARY RFIDCred.DLL 2 | 3 | EXPORTS 4 | DllCanUnloadNow PRIVATE 5 | DllGetClassObject PRIVATE 6 | -------------------------------------------------------------------------------- /AuthGen/AuthGen/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // AuthGen.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /AuthGen/AuthGen/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /AuthGen/AuthGen/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | #include 11 | #include 12 | 13 | 14 | 15 | // TODO: reference additional headers your program requires here 16 | -------------------------------------------------------------------------------- /RFIDCred/RFIDCred/Dll.h: -------------------------------------------------------------------------------- 1 | // 2 | // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF 3 | // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO 4 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 5 | // PARTICULAR PURPOSE. 6 | // 7 | // Copyright (c) 2006 Microsoft Corporation. All rights reserved. 8 | // 9 | // 10 | 11 | #pragma once 12 | 13 | // global dll hinstance 14 | extern HINSTANCE g_hinst; 15 | #define HINST_THISDLL g_hinst 16 | 17 | void DllAddRef(); 18 | void DllRelease(); 19 | -------------------------------------------------------------------------------- /AuthGen/AuthGen.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AuthGen", "AuthGen\AuthGen.vcxproj", "{F6EDB8A9-8240-433D-B348-CCE80A7B3A5F}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {F6EDB8A9-8240-433D-B348-CCE80A7B3A5F}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {F6EDB8A9-8240-433D-B348-CCE80A7B3A5F}.Debug|Win32.Build.0 = Debug|Win32 14 | {F6EDB8A9-8240-433D-B348-CCE80A7B3A5F}.Release|Win32.ActiveCfg = Release|Win32 15 | {F6EDB8A9-8240-433D-B348-CCE80A7B3A5F}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | RFID Windows Credential Provider 2 | ============= 3 | 4 | This is an example windows Credential Provider module which uses RFID to automate login process. 5 | 6 | As first step, download and install OpenSSL for windows from: https://slproweb.com/products/Win32OpenSSL.html 7 | Then add "include" and "lib" directories of OpenSSL in Visual Studio settings. 8 | 9 | Steps for storing encrypted credentials: 10 | - Go to AuthGen folder 11 | - Compile it using VS2010+ 12 | - Power on D-Login reader and put a blank RFID card on it. 13 | - Run AuthGen with a 32-byte key as first parameter, NT username and password as second and third parameters, example: 14 | AuthGen [32bytepassword] Administrator MyNTAdminPassword 15 | 16 | Now you need to install Credential Provider DLL: 17 | - Compile DLL with VS2010+ 18 | - Run install.bat 19 | 20 | You can simply test this DLL by logging off or restarting PC. 21 | For more information, visit: http://www.codeandsec.com/Windows-RFID-Login-Credential-Provider 22 | -------------------------------------------------------------------------------- /RFIDCred/RFIDCred.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RFIDCred", "RFIDCred\RFIDCred.vcxproj", "{7348AEE0-1F4A-4436-B782-6ABB694911AE}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Debug|x64 = Debug|x64 10 | Release|Win32 = Release|Win32 11 | Release|x64 = Release|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {7348AEE0-1F4A-4436-B782-6ABB694911AE}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {7348AEE0-1F4A-4436-B782-6ABB694911AE}.Debug|Win32.Build.0 = Debug|Win32 16 | {7348AEE0-1F4A-4436-B782-6ABB694911AE}.Debug|x64.ActiveCfg = Debug|x64 17 | {7348AEE0-1F4A-4436-B782-6ABB694911AE}.Debug|x64.Build.0 = Debug|x64 18 | {7348AEE0-1F4A-4436-B782-6ABB694911AE}.Release|Win32.ActiveCfg = Release|Win32 19 | {7348AEE0-1F4A-4436-B782-6ABB694911AE}.Release|Win32.Build.0 = Release|Win32 20 | {7348AEE0-1F4A-4436-B782-6ABB694911AE}.Release|x64.ActiveCfg = Release|x64 21 | {7348AEE0-1F4A-4436-B782-6ABB694911AE}.Release|x64.Build.0 = Release|x64 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | EndGlobal 27 | -------------------------------------------------------------------------------- /AuthGen/AuthGen/AuthGen.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | 26 | 27 | Source Files 28 | 29 | 30 | Source Files 31 | 32 | 33 | -------------------------------------------------------------------------------- /RFIDCred/RFIDCred/helpers.h: -------------------------------------------------------------------------------- 1 | // 2 | // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF 3 | // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO 4 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 5 | // PARTICULAR PURPOSE. 6 | // 7 | // Copyright (c) 2006 Microsoft Corporation. All rights reserved. 8 | // 9 | // Helper functions for copying parameters and packaging the buffer 10 | // for GetSerialization. 11 | 12 | #pragma once 13 | #include "common.h" 14 | #include 15 | #include 16 | 17 | #pragma warning(push) 18 | #pragma warning(disable : 4995) 19 | #include 20 | #pragma warning(pop) 21 | 22 | 23 | 24 | //makes a copy of a field descriptor using CoTaskMemAlloc 25 | HRESULT FieldDescriptorCoAllocCopy( 26 | const CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR& rcpfd, 27 | CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR** ppcpfd 28 | ); 29 | 30 | //makes a copy of a field descriptor on the normal heap 31 | HRESULT FieldDescriptorCopy( 32 | const CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR& rcpfd, 33 | CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR* pcpfd 34 | ); 35 | 36 | //creates a UNICODE_STRING from a NULL-terminated string 37 | HRESULT UnicodeStringInitWithString( 38 | PWSTR pwz, 39 | UNICODE_STRING* pus 40 | ); 41 | 42 | //initializes a KERB_INTERACTIVE_UNLOCK_LOGON with weak references to the provided credentials 43 | HRESULT KerbInteractiveUnlockLogonInit( 44 | PWSTR pwzDomain, 45 | PWSTR pwzUsername, 46 | PWSTR pwzPassword, 47 | CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus, 48 | KERB_INTERACTIVE_UNLOCK_LOGON* pkiul 49 | ); 50 | 51 | //packages the credentials into the buffer that the system expects 52 | HRESULT KerbInteractiveUnlockLogonPack( 53 | const KERB_INTERACTIVE_UNLOCK_LOGON& rkiulIn, 54 | BYTE** prgb, 55 | DWORD* pcb 56 | ); 57 | 58 | //get the authentication package that will be used for our logon attempt 59 | HRESULT RetrieveNegotiateAuthPackage( 60 | ULONG * pulAuthPackage 61 | ); 62 | 63 | 64 | //encrypt a password (if necessary) and copy it; if not, just copy it 65 | HRESULT ProtectIfNecessaryAndCopyPassword( 66 | PWSTR pwzPassword, 67 | CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus, 68 | PWSTR* ppwzProtectedPassword); 69 | 70 | HRESULT KerbInteractiveUnlockLogonRepackNative( 71 | __in_bcount(cbWow) BYTE* rgbWow, 72 | DWORD cbWow, 73 | __out_bcount(*pcbNative) BYTE** prgbNative, 74 | __out DWORD* pcbNative); 75 | 76 | void KerbInteractiveUnlockLogonUnpackInPlace( 77 | __inout_bcount(cb) KERB_INTERACTIVE_UNLOCK_LOGON* pkiul, 78 | DWORD cb 79 | ); 80 | 81 | HRESULT DomainUsernameStringAlloc( 82 | const PWSTR pwszDomain, 83 | const PWSTR pwszUsername, 84 | __deref_out PWSTR* ppwszDomainUsername); 85 | -------------------------------------------------------------------------------- /RFIDCred/RFIDCred/common.h: -------------------------------------------------------------------------------- 1 | // 2 | // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF 3 | // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO 4 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 5 | // PARTICULAR PURPOSE. 6 | // 7 | // Copyright (c) 2006 Microsoft Corporation. All rights reserved. 8 | // 9 | // This file contains some global variables that describe what our 10 | // sample tile looks like. For example, it defines what fields a tile has 11 | // and which fields show in which states of LogonUI. 12 | 13 | #pragma once 14 | #include 15 | #include 16 | #define SECURITY_WIN32 17 | #include 18 | #include 19 | 20 | #define MAX_ULONG ((ULONG)(-1)) 21 | 22 | // The indexes of each of the fields in our credential provider's tiles. 23 | enum SAMPLE_FIELD_ID 24 | { 25 | SFI_TILEIMAGE = 0, 26 | SFI_USERNAME = 1, 27 | SFI_PASSWORD = 2, 28 | SFI_SUBMIT_BUTTON = 3, 29 | SFI_NUM_FIELDS = 4, // Note: if new fields are added, keep NUM_FIELDS last. This is used as a count of the number of fields 30 | }; 31 | 32 | // The first value indicates when the tile is displayed (selected, not selected) 33 | // the second indicates things like whether the field is enabled, whether it has key focus, etc. 34 | struct FIELD_STATE_PAIR 35 | { 36 | CREDENTIAL_PROVIDER_FIELD_STATE cpfs; 37 | CREDENTIAL_PROVIDER_FIELD_INTERACTIVE_STATE cpfis; 38 | }; 39 | 40 | // These two arrays are seperate because a credential provider might 41 | // want to set up a credential with various combinations of field state pairs 42 | // and field descriptors. 43 | 44 | // The field state value indicates whether the field is displayed 45 | // in the selected tile, the deselected tile, or both. 46 | // The Field interactive state indicates when 47 | static const FIELD_STATE_PAIR s_rgFieldStatePairs[] = 48 | { 49 | { CPFS_DISPLAY_IN_BOTH, CPFIS_NONE }, // SFI_TILEIMAGE 50 | { CPFS_DISPLAY_IN_BOTH, CPFIS_NONE }, // SFI_USERNAME 51 | { CPFS_DISPLAY_IN_SELECTED_TILE, CPFIS_FOCUSED }, // SFI_PASSWORD 52 | { CPFS_DISPLAY_IN_SELECTED_TILE, CPFIS_NONE }, // SFI_SUBMIT_BUTTON 53 | }; 54 | 55 | // Field descriptors for unlock and logon. 56 | // The first field is the index of the field. 57 | // The second is the type of the field. 58 | // The third is the name of the field, NOT the value which will appear in the field. 59 | static const CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR s_rgCredProvFieldDescriptors[] = 60 | { 61 | { SFI_TILEIMAGE, CPFT_TILE_IMAGE, L"Image" }, 62 | { SFI_USERNAME, CPFT_LARGE_TEXT, L"Username" }, 63 | { SFI_PASSWORD, CPFT_PASSWORD_TEXT, L"Password" }, 64 | { SFI_SUBMIT_BUTTON, CPFT_SUBMIT_BUTTON, L"Submit" }, 65 | }; -------------------------------------------------------------------------------- /RFIDCred/RFIDCred/RFIDCred.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav 15 | 16 | 17 | {e796b93d-db30-4e4e-afdc-2d1e4a424e18} 18 | 19 | 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | 38 | 39 | Header Files 40 | 41 | 42 | Header Files 43 | 44 | 45 | Header Files 46 | 47 | 48 | Header Files 49 | 50 | 51 | Header Files 52 | 53 | 54 | Header Files 55 | 56 | 57 | Header Files 58 | 59 | 60 | 61 | 62 | Resource Files 63 | 64 | 65 | 66 | 67 | Resource Files 68 | 69 | 70 | Resource Files 71 | 72 | 73 | Utilities 74 | 75 | 76 | Utilities 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /RFIDCred/RFIDCred/CSampleProvider.h: -------------------------------------------------------------------------------- 1 | // 2 | // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF 3 | // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO 4 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 5 | // PARTICULAR PURPOSE. 6 | // 7 | // Copyright (c) Microsoft Corporation. All rights reserved. 8 | // 9 | // 10 | 11 | #pragma once 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include "CSampleCredential.h" 18 | #include "helpers.h" 19 | 20 | #define MAX_CREDENTIALS 3 21 | 22 | class CSampleProvider : public ICredentialProvider 23 | { 24 | public: 25 | // IUnknown 26 | STDMETHOD_(ULONG, AddRef)() 27 | { 28 | return _cRef++; 29 | } 30 | 31 | STDMETHOD_(ULONG, Release)() 32 | { 33 | LONG cRef = _cRef--; 34 | if (!cRef) 35 | { 36 | delete this; 37 | } 38 | return cRef; 39 | } 40 | 41 | STDMETHOD (QueryInterface)(REFIID riid, void** ppv) 42 | { 43 | HRESULT hr; 44 | if (IID_IUnknown == riid || 45 | IID_ICredentialProvider == riid) 46 | { 47 | *ppv = this; 48 | reinterpret_cast(*ppv)->AddRef(); 49 | hr = S_OK; 50 | } 51 | else 52 | { 53 | *ppv = NULL; 54 | hr = E_NOINTERFACE; 55 | } 56 | return hr; 57 | } 58 | 59 | public: 60 | IFACEMETHODIMP SetUsageScenario(CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus, DWORD dwFlags); 61 | IFACEMETHODIMP SetSerialization(const CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcs); 62 | 63 | IFACEMETHODIMP Advise(__in ICredentialProviderEvents* pcpe, UINT_PTR upAdviseContext); 64 | IFACEMETHODIMP UnAdvise(); 65 | 66 | IFACEMETHODIMP GetFieldDescriptorCount(__out DWORD* pdwCount); 67 | IFACEMETHODIMP GetFieldDescriptorAt(DWORD dwIndex, __deref_out CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR** ppcpfd); 68 | 69 | IFACEMETHODIMP GetCredentialCount(__out DWORD* pdwCount, 70 | __out DWORD* pdwDefault, 71 | __out BOOL* pbAutoLogonWithDefault); 72 | IFACEMETHODIMP GetCredentialAt(DWORD dwIndex, 73 | __out ICredentialProviderCredential** ppcpc); 74 | 75 | friend HRESULT CSampleProvider_CreateInstance(REFIID riid, __deref_out void** ppv); 76 | 77 | protected: 78 | CSampleProvider(); 79 | __override ~CSampleProvider(); 80 | 81 | private: 82 | 83 | HRESULT _EnumerateOneCredential(__in DWORD dwCredentialIndex, 84 | __in PCWSTR pwzUsername 85 | ); 86 | 87 | // Create/free enumerated credentials. 88 | HRESULT _CreateEnumeratedCredentials(); 89 | void _ReleaseEnumeratedCredentials(); 90 | 91 | HRESULT _EnumerateCredentials(bool bAlreadyHaveSetSerializationCred = false); //this enumerates the normal set of 2 creds 92 | HRESULT _EnumerateSetSerialization(); //this will enumerate one tile with the contents of _pkiulSetSerialization 93 | 94 | private: 95 | LONG _cRef; 96 | CSampleCredential *_rgpCredentials[MAX_CREDENTIALS]; // Pointers to the credentials which will be enumerated by 97 | // this Provider. 98 | KERB_INTERACTIVE_UNLOCK_LOGON * _pkiulSetSerialization; 99 | CREDENTIAL_PROVIDER_USAGE_SCENARIO _cpus; 100 | DWORD _dwCredUIFlags; 101 | bool _bRecreateEnumeratedCredentials; 102 | bool _bAutoSubmitSetSerializationCred; 103 | bool _bDefaultToFirstCredential; 104 | }; -------------------------------------------------------------------------------- /AuthGen/AuthGen/AuthGen.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include 3 | #include 4 | #include 5 | #pragma comment(lib, "libeay32.lib") 6 | 7 | typedef long (*fReaderOpen) (void); 8 | typedef long (*fReaderClose) (void); 9 | typedef long (*fLinearWrite) (PBYTE, short, short, short *, unsigned char, unsigned char); 10 | 11 | int aes_init(unsigned char *key_data, int key_data_len, unsigned char *salt, EVP_CIPHER_CTX *e_ctx, EVP_CIPHER_CTX *d_ctx) 12 | { 13 | int i, nrounds = 5; 14 | unsigned char key[32], iv[32]; 15 | i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt, key_data, key_data_len, nrounds, key, iv); 16 | if (i != 32) return -1; 17 | EVP_CIPHER_CTX_init(e_ctx); 18 | EVP_EncryptInit_ex(e_ctx, EVP_aes_256_cbc(), NULL, key, iv); 19 | EVP_CIPHER_CTX_init(d_ctx); 20 | EVP_DecryptInit_ex(d_ctx, EVP_aes_256_cbc(), NULL, key, iv); 21 | return 0; 22 | } 23 | 24 | unsigned char *aes_encrypt(EVP_CIPHER_CTX *e, unsigned char *plaintext, int *len) 25 | { 26 | int c_len = *len + AES_BLOCK_SIZE, f_len = 0; 27 | unsigned char *ciphertext = (unsigned char *)malloc(c_len); 28 | 29 | EVP_EncryptInit_ex(e, NULL, NULL, NULL, NULL); 30 | 31 | EVP_EncryptUpdate(e, ciphertext, &c_len, plaintext, *len); 32 | 33 | EVP_EncryptFinal_ex(e, ciphertext+c_len, &f_len); 34 | *len = c_len + f_len; 35 | return ciphertext; 36 | } 37 | 38 | int main(int argc, char* argv[]) 39 | { 40 | 41 | if (argc != 4) 42 | { 43 | printf("\nUsage: AuthGen.exe 32-bytepassword NTUsername NTPassword\n"); 44 | printf("Example: AuthGen qIys9M9HmEywoHKy8nKAS3eq90YPt1Er Administrator MYAdminPass\n"); 45 | return -1; 46 | } 47 | 48 | if (strlen(argv[1]) != 32) 49 | { 50 | printf("Please enter a 32-byte key string as parameter\n"); 51 | return -1; 52 | } 53 | 54 | if (strlen(argv[2]) > 32 || strlen(argv[3]) > 64) 55 | { 56 | printf("\nMaximum username length: 32\nMaximum password length: 64\n"); 57 | return 0; 58 | } 59 | 60 | int SecretLen = strlen(argv[2]) + strlen(argv[3]) + 1; 61 | char* Secret = (char*)malloc(SecretLen); 62 | sprintf(Secret, "%s|%s", argv[2], argv[3]); 63 | 64 | HMODULE hlib = LoadLibraryA("uFCoder1x.dll"); 65 | if (hlib == NULL) 66 | { 67 | printf("Please copy uFCoder1x.dll in %PATH%\n"); 68 | return 0; 69 | } 70 | 71 | fReaderOpen ReaderOpen = (fReaderOpen) GetProcAddress(hlib, "ReaderOpen"); 72 | fReaderClose ReaderClose = (fReaderClose) GetProcAddress(hlib, "ReaderClose"); 73 | fLinearWrite LinearWrite = (fLinearWrite) GetProcAddress(hlib, "LinearWrite"); 74 | if (ReaderClose == NULL || ReaderOpen == NULL || LinearWrite == NULL) 75 | { 76 | printf("Invalid DLL, please check DLL."); 77 | return 0; 78 | } 79 | 80 | long retval = ReaderOpen(); 81 | if (retval != 0) 82 | { 83 | printf("Unable to open reader"); 84 | return 0; 85 | } 86 | 87 | DWORD cbBlob; 88 | BYTE* pbBlob; 89 | DWORD dwResult; 90 | HCRYPTPROV hProv; 91 | HCRYPTKEY hKey; 92 | HCRYPTHASH hHash = 0; 93 | unsigned char *key_data; 94 | unsigned char *ciphertext; 95 | int key_data_len, i; 96 | cbBlob = 32; 97 | pbBlob = (BYTE*)malloc(cbBlob + 1); 98 | memset(pbBlob, 0, cbBlob + 1); 99 | for (int i = 0; i < 32; i++) 100 | { 101 | pbBlob[i] = argv[1][i]; 102 | } 103 | 104 | pbBlob[32] = 0x00; 105 | 106 | EVP_CIPHER_CTX en, de; 107 | unsigned int salt[] = {12345, 54321}; 108 | key_data = (unsigned char *)argv[1]; 109 | key_data_len = strlen(argv[1]); 110 | if (aes_init(key_data, key_data_len, (unsigned char *)&salt, &en, &de)) 111 | { 112 | printf("Couldn't initialize AES cipher\n"); 113 | return -1; 114 | } 115 | 116 | ciphertext = aes_encrypt(&en, (unsigned char *)Secret, &SecretLen); 117 | 118 | char SecretKeyFile[MAX_PATH]; 119 | FILE* fp; 120 | GetWindowsDirectory(SecretKeyFile, MAX_PATH); 121 | strcat(SecretKeyFile, "\\master.passwd"); 122 | fp = fopen(SecretKeyFile, "w"); 123 | if (!fp) 124 | { 125 | free(ciphertext); 126 | EVP_CIPHER_CTX_cleanup(&en); 127 | EVP_CIPHER_CTX_cleanup(&de); 128 | printf("Failed to open MyAuth file. Are you running as root?\n"); 129 | return -1; 130 | } 131 | 132 | fwrite(ciphertext, 1, SecretLen, fp); 133 | fclose(fp); 134 | short bytesret; 135 | LinearWrite(pbBlob, 0, SecretLen, &bytesret, 0x60, 0); 136 | free(ciphertext); 137 | EVP_CIPHER_CTX_cleanup(&en); 138 | EVP_CIPHER_CTX_cleanup(&de); 139 | printf("Credentials stored. Please install Credential Providerds DLL.\n"); 140 | ReaderClose(); 141 | return 0; 142 | } 143 | -------------------------------------------------------------------------------- /AuthGen/AuthGen/AuthGen.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {F6EDB8A9-8240-433D-B348-CCE80A7B3A5F} 15 | Win32Proj 16 | AuthGen 17 | 18 | 19 | 20 | Application 21 | true 22 | MultiByte 23 | 24 | 25 | Application 26 | false 27 | true 28 | Unicode 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | true 42 | C:\OpenSSL\include;$(IncludePath) 43 | C:\OpenSSL\lib;$(LibraryPath) 44 | 45 | 46 | false 47 | 48 | 49 | 50 | Use 51 | Level3 52 | Disabled 53 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 54 | 55 | 56 | Console 57 | true 58 | 59 | 60 | 61 | 62 | Level3 63 | Use 64 | MaxSpeed 65 | true 66 | true 67 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 68 | 69 | 70 | Console 71 | true 72 | true 73 | true 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | Create 84 | Create 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /RFIDCred/RFIDCred/Dll.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF 3 | // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO 4 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 5 | // PARTICULAR PURPOSE. 6 | // 7 | // Copyright (c) 2006 Microsoft Corporation. All rights reserved. 8 | // 9 | // Standard dll required functions and class factory implementation. 10 | 11 | #include 12 | #include 13 | #include "Dll.h" 14 | #include "guid.h" 15 | 16 | static LONG g_cRef = 0; // global dll reference count 17 | 18 | // IClassFactory /////////////////////////////////////////////////////////////////////// 19 | 20 | extern HRESULT CSampleProvider_CreateInstance(REFIID riid, void** ppv); 21 | 22 | HINSTANCE g_hinst = NULL; // global dll hinstance 23 | 24 | 25 | class CClassFactory : public IClassFactory 26 | { 27 | public: 28 | // IUnknown 29 | STDMETHOD_(ULONG, AddRef)() 30 | { 31 | return _cRef++; 32 | } 33 | 34 | STDMETHOD_(ULONG, Release)() 35 | { 36 | LONG cRef = _cRef--; 37 | if (!cRef) 38 | { 39 | delete this; 40 | } 41 | return cRef; 42 | } 43 | 44 | STDMETHOD (QueryInterface)(REFIID riid, void** ppv) 45 | { 46 | HRESULT hr; 47 | if (ppv != NULL) 48 | { 49 | if (IID_IClassFactory == riid || IID_IUnknown == riid) 50 | { 51 | *ppv = static_cast(this); 52 | reinterpret_cast(*ppv)->AddRef(); 53 | hr = S_OK; 54 | } 55 | else 56 | { 57 | *ppv = NULL; 58 | hr = E_NOINTERFACE; 59 | } 60 | } 61 | else 62 | { 63 | hr = E_INVALIDARG; 64 | } 65 | return hr; 66 | } 67 | 68 | // IClassFactory 69 | STDMETHOD (CreateInstance)(IUnknown* pUnkOuter, REFIID riid, void** ppv) 70 | { 71 | HRESULT hr; 72 | if (!pUnkOuter) 73 | { 74 | hr = CSampleProvider_CreateInstance(riid, ppv); 75 | } 76 | else 77 | { 78 | hr = CLASS_E_NOAGGREGATION; 79 | } 80 | return hr; 81 | } 82 | 83 | STDMETHOD (LockServer)(BOOL bLock) 84 | { 85 | if (bLock) 86 | { 87 | DllAddRef(); 88 | } 89 | else 90 | { 91 | DllRelease(); 92 | } 93 | return S_OK; 94 | } 95 | 96 | private: 97 | CClassFactory() : _cRef(1) {} 98 | ~CClassFactory(){} 99 | 100 | private: 101 | LONG _cRef; 102 | 103 | friend HRESULT CClassFactory_CreateInstance(REFCLSID rclsid, REFIID riid, void** ppv); 104 | }; 105 | 106 | HRESULT CClassFactory_CreateInstance(REFCLSID rclsid, REFIID riid, void** ppv) 107 | { 108 | HRESULT hr; 109 | if (CLSID_CSampleProvider == rclsid) 110 | { 111 | CClassFactory* pcf = new CClassFactory; 112 | if (pcf) 113 | { 114 | hr = pcf->QueryInterface(riid, ppv); 115 | pcf->Release(); 116 | } 117 | else 118 | { 119 | hr = E_OUTOFMEMORY; 120 | } 121 | } 122 | else 123 | { 124 | hr = CLASS_E_CLASSNOTAVAILABLE; 125 | } 126 | return hr; 127 | } 128 | 129 | // DLL Functions /////////////////////////////////////////////////////////////////////// 130 | 131 | BOOL WINAPI DllMain( 132 | HINSTANCE hinstDll, 133 | DWORD dwReason, 134 | LPVOID pReserved 135 | ) 136 | { 137 | UNREFERENCED_PARAMETER(pReserved); 138 | 139 | switch (dwReason) 140 | { 141 | case DLL_PROCESS_ATTACH: 142 | DisableThreadLibraryCalls(hinstDll); 143 | break; 144 | case DLL_PROCESS_DETACH: 145 | case DLL_THREAD_ATTACH: 146 | case DLL_THREAD_DETACH: 147 | break; 148 | } 149 | 150 | g_hinst = hinstDll; 151 | return TRUE; 152 | 153 | } 154 | 155 | void DllAddRef() 156 | { 157 | InterlockedIncrement(&g_cRef); 158 | } 159 | 160 | void DllRelease() 161 | { 162 | InterlockedDecrement(&g_cRef); 163 | } 164 | 165 | // DLL entry point. 166 | STDAPI DllCanUnloadNow() 167 | { 168 | HRESULT hr; 169 | 170 | if (g_cRef > 0) 171 | { 172 | hr = S_FALSE; // cocreated objects still exist, don't unload 173 | } 174 | else 175 | { 176 | hr = S_OK; // refcount is zero, ok to unload 177 | } 178 | 179 | return hr; 180 | } 181 | 182 | // DLL entry point. 183 | STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void** ppv) 184 | { 185 | return CClassFactory_CreateInstance(rclsid, riid, ppv); 186 | } 187 | 188 | -------------------------------------------------------------------------------- /RFIDCred/RFIDCred/CSampleCredential.h: -------------------------------------------------------------------------------- 1 | // 2 | // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF 3 | // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO 4 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 5 | // PARTICULAR PURPOSE. 6 | // 7 | // Copyright (c) 2006 Microsoft Corporation. All rights reserved. 8 | // 9 | // CSampleCredential is our implementation of ICredentialProviderCredential. 10 | // ICredentialProviderCredential is what LogonUI uses to let a credential 11 | // provider specify what a user tile looks like and then tell it what the 12 | // user has entered into the tile. ICredentialProviderCredential is also 13 | // responsible for packaging up the users credentials into a buffer that 14 | // LogonUI then sends on to LSA. 15 | 16 | #pragma once 17 | 18 | #include 19 | #include 20 | #include 21 | #include "helpers.h" 22 | #include "dll.h" 23 | #include "resource.h" 24 | 25 | class CSampleCredential : public ICredentialProviderCredential 26 | { 27 | public: 28 | // IUnknown 29 | STDMETHOD_(ULONG, AddRef)() 30 | { 31 | return _cRef++; 32 | } 33 | 34 | STDMETHOD_(ULONG, Release)() 35 | { 36 | LONG cRef = _cRef--; 37 | if (!cRef) 38 | { 39 | delete this; 40 | } 41 | return cRef; 42 | } 43 | 44 | STDMETHOD (QueryInterface)(REFIID riid, void** ppv) 45 | { 46 | HRESULT hr; 47 | if (ppv != NULL) 48 | { 49 | if (IID_IUnknown == riid || 50 | IID_ICredentialProviderCredential == riid) 51 | { 52 | *ppv = static_cast(this); 53 | reinterpret_cast(*ppv)->AddRef(); 54 | hr = S_OK; 55 | } 56 | else 57 | { 58 | *ppv = NULL; 59 | hr = E_NOINTERFACE; 60 | } 61 | } 62 | else 63 | { 64 | hr = E_INVALIDARG; 65 | } 66 | return hr; 67 | } 68 | public: 69 | // ICredentialProviderCredential 70 | IFACEMETHODIMP Advise(ICredentialProviderCredentialEvents* pcpce); 71 | IFACEMETHODIMP UnAdvise(); 72 | 73 | IFACEMETHODIMP SetSelected(BOOL* pbAutoLogon); 74 | IFACEMETHODIMP SetDeselected(); 75 | 76 | IFACEMETHODIMP GetFieldState(DWORD dwFieldID, 77 | CREDENTIAL_PROVIDER_FIELD_STATE* pcpfs, 78 | CREDENTIAL_PROVIDER_FIELD_INTERACTIVE_STATE* pcpfis); 79 | 80 | IFACEMETHODIMP GetStringValue(DWORD dwFieldID, PWSTR* ppwz); 81 | IFACEMETHODIMP GetBitmapValue(DWORD dwFieldID, HBITMAP* phbmp); 82 | IFACEMETHODIMP GetCheckboxValue(DWORD dwFieldID, BOOL* pbChecked, PWSTR* ppwzLabel); 83 | IFACEMETHODIMP GetComboBoxValueCount(DWORD dwFieldID, DWORD* pcItems, DWORD* pdwSelectedItem); 84 | IFACEMETHODIMP GetComboBoxValueAt(DWORD dwFieldID, DWORD dwItem, PWSTR* ppwzItem); 85 | IFACEMETHODIMP GetSubmitButtonValue(DWORD dwFieldID, DWORD* pdwAdjacentTo); 86 | 87 | IFACEMETHODIMP SetStringValue(DWORD dwFieldID, PCWSTR pwz); 88 | IFACEMETHODIMP SetCheckboxValue(DWORD dwFieldID, BOOL bChecked); 89 | IFACEMETHODIMP SetComboBoxSelectedValue(DWORD dwFieldID, DWORD dwSelectedItem); 90 | IFACEMETHODIMP CommandLinkClicked(DWORD dwFieldID); 91 | 92 | IFACEMETHODIMP GetSerialization(CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE* pcpgsr, 93 | CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcs, 94 | PWSTR* ppwzOptionalStatusText, 95 | CREDENTIAL_PROVIDER_STATUS_ICON* pcpsiOptionalStatusIcon); 96 | IFACEMETHODIMP ReportResult(NTSTATUS ntsStatus, 97 | NTSTATUS ntsSubstatus, 98 | PWSTR* ppwzOptionalStatusText, 99 | CREDENTIAL_PROVIDER_STATUS_ICON* pcpsiOptionalStatusIcon); 100 | 101 | public: 102 | HRESULT Initialize(CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus, 103 | const CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR* rgcpfd, 104 | const FIELD_STATE_PAIR* rgfsp, 105 | DWORD dwFlags, 106 | PCWSTR pwzUsername, 107 | PCWSTR pwzPassword = NULL); 108 | 109 | 110 | CSampleCredential(); 111 | 112 | virtual ~CSampleCredential(); 113 | 114 | private: 115 | DWORD _dwFlags; // The flags representing the Credui Options 116 | LONG _cRef; 117 | 118 | CREDENTIAL_PROVIDER_USAGE_SCENARIO _cpus; // The usage scenario for which we were enumerated. 119 | 120 | CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR _rgCredProvFieldDescriptors[SFI_NUM_FIELDS]; // An array holding the type 121 | // and name of each field in 122 | // the tile. 123 | 124 | FIELD_STATE_PAIR _rgFieldStatePairs[SFI_NUM_FIELDS]; // An array holding the state 125 | // of each field in the tile. 126 | 127 | PWSTR _rgFieldStrings[SFI_NUM_FIELDS]; // An array holding the string 128 | // value of each field. This is 129 | // different from the name of 130 | // the field held in 131 | // _rgCredProvFieldDescriptors. 132 | ICredentialProviderCredentialEvents* _pCredProvCredentialEvents; 133 | 134 | }; 135 | -------------------------------------------------------------------------------- /RFIDCred/RFIDCred/RFIDCred.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 13 | 16 | 17 | 18 | 19 | 20 | 26 | 29 | 32 | 35 | 38 | 41 | 50 | 53 | 56 | 59 | 75 | 78 | 81 | 84 | 87 | 90 | 93 | 96 | 100 | 101 | 107 | 110 | 113 | 116 | 119 | 122 | 129 | 132 | 135 | 138 | 149 | 152 | 155 | 158 | 161 | 164 | 167 | 170 | 173 | 174 | 180 | 183 | 186 | 189 | 192 | 196 | 205 | 208 | 211 | 214 | 231 | 234 | 237 | 240 | 243 | 246 | 249 | 252 | 256 | 257 | 263 | 266 | 269 | 272 | 275 | 279 | 286 | 289 | 292 | 295 | 307 | 310 | 313 | 316 | 319 | 322 | 325 | 328 | 331 | 332 | 333 | 334 | 335 | 336 | 341 | 344 | 345 | 348 | 349 | 352 | 353 | 356 | 357 | 360 | 361 | 362 | 367 | 370 | 371 | 374 | 375 | 378 | 379 | 382 | 383 | 386 | 387 | 390 | 391 | 394 | 395 | 396 | 401 | 404 | 405 | 408 | 409 | 412 | 413 | 414 | 417 | 420 | 421 | 424 | 425 | 426 | 429 | 430 | 431 | 432 | 433 | 434 | -------------------------------------------------------------------------------- /RFIDCred/RFIDCred/RFIDCred.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {7348AEE0-1F4A-4436-B782-6ABB694911AE} 23 | RFIDCred 24 | 25 | 26 | 27 | DynamicLibrary 28 | 29 | 30 | DynamicLibrary 31 | 32 | 33 | DynamicLibrary 34 | 35 | 36 | DynamicLibrary 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | <_ProjectFileVersion>10.0.40219.1 56 | $(SolutionDir)$(Configuration)\ 57 | $(Configuration)\ 58 | false 59 | true 60 | $(SolutionDir)$(Configuration)\ 61 | $(Configuration)\ 62 | true 63 | $(SolutionDir)$(Platform)\$(Configuration)\ 64 | $(Platform)\$(Configuration)\ 65 | false 66 | true 67 | $(SolutionDir)$(Platform)\$(Configuration)\ 68 | $(Platform)\$(Configuration)\ 69 | true 70 | AllRules.ruleset 71 | 72 | 73 | AllRules.ruleset 74 | 75 | 76 | AllRules.ruleset 77 | 78 | 79 | AllRules.ruleset 80 | 81 | 82 | C:\OpenSSL\include;$(IncludePath) 83 | C:\OpenSSL\lib;$(LibraryPath) 84 | 85 | 86 | 87 | Disabled 88 | Default 89 | C:\Program Files\Microsoft SDKs\Windows\v1.0\Include;%(AdditionalIncludeDirectories) 90 | Level4 91 | true 92 | EditAndContinue 93 | 94 | 95 | secur32.lib;shlwapi.lib;gdi32.lib;ole32.lib;user32.lib;advapi32.lib;credui.lib;%(AdditionalDependencies) 96 | LinkVerboseLib 97 | $(OutDir)$(ProjectName).dll 98 | C:\program Files\microsoft sdKs\Windows\v1.0\Lib;%(AdditionalLibraryDirectories) 99 | RFIDCred.def 100 | secur32.lib;%(AddModuleNamesToAssembly) 101 | true 102 | true 103 | $(TargetDir)$(TargetName).pdb 104 | false 105 | false 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | C:\Program Files\Microsoft SDKs\Windows\v1.0\Include;%(AdditionalIncludeDirectories) 115 | Level4 116 | true 117 | ProgramDatabase 118 | 119 | 120 | secur32.lib;shlwapi.lib;gdi32.lib;ole32.lib;user32.lib;advapi32.lib;credui.lib;%(AdditionalDependencies) 121 | LinkVerboseLib 122 | $(OutDir)$(ProjectName).dll 123 | C:\program Files\microsoft sdKs\Windows\v1.0\Lib;%(AdditionalLibraryDirectories) 124 | samplecreduicredentialprovider.def 125 | secur32.lib;%(AddModuleNamesToAssembly) 126 | true 127 | 128 | 129 | 130 | 131 | X64 132 | 133 | 134 | Disabled 135 | Default 136 | C:\Program Files\Microsoft SDKs\Windows\v1.0\Include;%(AdditionalIncludeDirectories) 137 | Level4 138 | true 139 | ProgramDatabase 140 | 141 | 142 | secur32.lib;shlwapi.lib;gdi32.lib;ole32.lib;user32.lib;advapi32.lib;credui.lib;%(AdditionalDependencies) 143 | LinkVerboseLib 144 | $(OutDir)$(ProjectName).dll 145 | C:\program Files\microsoft sdKs\Windows\v1.0\Lib;%(AdditionalLibraryDirectories) 146 | samplecreduicredentialprovider.def 147 | secur32.lib;%(AddModuleNamesToAssembly) 148 | true 149 | true 150 | $(TargetDir)$(TargetName).pdb 151 | false 152 | false 153 | MachineX64 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | X64 163 | 164 | 165 | C:\Program Files\Microsoft SDKs\Windows\v1.0\Include;%(AdditionalIncludeDirectories) 166 | Level4 167 | true 168 | ProgramDatabase 169 | 170 | 171 | secur32.lib;shlwapi.lib;gdi32.lib;ole32.lib;user32.lib;advapi32.lib;credui.lib;%(AdditionalDependencies) 172 | LinkVerboseLib 173 | $(OutDir)$(ProjectName).dll 174 | C:\program Files\microsoft sdKs\Windows\v1.0\Lib;%(AdditionalLibraryDirectories) 175 | samplecreduicredentialprovider.def 176 | secur32.lib;%(AddModuleNamesToAssembly) 177 | true 178 | MachineX64 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | -------------------------------------------------------------------------------- /RFIDCred/RFIDCred/csamplecredential.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF 3 | // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO 4 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 5 | // PARTICULAR PURPOSE. 6 | // 7 | // Copyright (c) 2006 Microsoft Corporation. All rights reserved. 8 | // 9 | // 10 | 11 | #ifndef WIN32_NO_STATUS 12 | #include 13 | #define WIN32_NO_STATUS 14 | #endif 15 | #include 16 | #include 17 | #include "CSampleCredential.h" 18 | #include "guid.h" 19 | #pragma warning(disable:4995) 20 | #pragma warning(disable:4996) 21 | #pragma warning(disable:4101) 22 | typedef long (*fReaderOpen) (void); 23 | typedef long (*fReaderClose) (void); 24 | typedef long (*fLinearRead) (PBYTE, short, short, short *, unsigned char, unsigned char); 25 | #pragma comment(lib, "libeay32.lib") 26 | #include 27 | #include 28 | 29 | // CSampleCredential //////////////////////////////////////////////////////// 30 | 31 | int aes_init(unsigned char *key_data, int key_data_len, unsigned char *salt, EVP_CIPHER_CTX *e_ctx, EVP_CIPHER_CTX *d_ctx) 32 | { 33 | int i, nrounds = 5; 34 | unsigned char key[32], iv[32]; 35 | i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt, key_data, key_data_len, nrounds, key, iv); 36 | if (i != 32) return -1; 37 | 38 | EVP_CIPHER_CTX_init(e_ctx); 39 | EVP_EncryptInit_ex(e_ctx, EVP_aes_256_cbc(), NULL, key, iv); 40 | EVP_CIPHER_CTX_init(d_ctx); 41 | EVP_DecryptInit_ex(d_ctx, EVP_aes_256_cbc(), NULL, key, iv); 42 | 43 | return 0; 44 | } 45 | 46 | unsigned char *aes_decrypt(EVP_CIPHER_CTX *e, unsigned char *ciphertext, int *len) 47 | { 48 | int p_len = *len, f_len = 0; 49 | unsigned char *plaintext = (BYTE*) malloc(p_len + AES_BLOCK_SIZE); 50 | 51 | EVP_DecryptInit_ex(e, NULL, NULL, NULL, NULL); 52 | EVP_DecryptUpdate(e, plaintext, &p_len, ciphertext, *len); 53 | EVP_DecryptFinal_ex(e, plaintext+p_len, &f_len); 54 | 55 | *len = p_len + f_len; 56 | return plaintext; 57 | } 58 | 59 | CSampleCredential::CSampleCredential(): 60 | _cRef(1), 61 | _pCredProvCredentialEvents(NULL) 62 | { 63 | DllAddRef(); 64 | 65 | ZeroMemory(_rgCredProvFieldDescriptors, sizeof(_rgCredProvFieldDescriptors)); 66 | ZeroMemory(_rgFieldStatePairs, sizeof(_rgFieldStatePairs)); 67 | ZeroMemory(_rgFieldStrings, sizeof(_rgFieldStrings)); 68 | } 69 | 70 | CSampleCredential::~CSampleCredential() 71 | { 72 | if (_rgFieldStrings[SFI_PASSWORD]) 73 | { 74 | // CoTaskMemFree (below) deals with NULL, but StringCchLength does not. 75 | size_t lenPassword; 76 | HRESULT hr = StringCchLengthW(_rgFieldStrings[SFI_PASSWORD], 128, &(lenPassword)); 77 | if (SUCCEEDED(hr)) 78 | { 79 | SecureZeroMemory(_rgFieldStrings[SFI_PASSWORD], lenPassword * sizeof(*_rgFieldStrings[SFI_PASSWORD])); 80 | } 81 | else 82 | { 83 | // TODO: Determine how to handle count error here. 84 | } 85 | } 86 | for (int i = 0; i < ARRAYSIZE(_rgFieldStrings); i++) 87 | { 88 | CoTaskMemFree(_rgFieldStrings[i]); 89 | CoTaskMemFree(_rgCredProvFieldDescriptors[i].pszLabel); 90 | } 91 | 92 | DllRelease(); 93 | } 94 | 95 | // Initializes one credential with the field information passed in. 96 | // Set the value of the SFI_USERNAME field to pwzUsername. 97 | HRESULT CSampleCredential::Initialize( 98 | CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus, 99 | const CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR* rgcpfd, 100 | const FIELD_STATE_PAIR* rgfsp, 101 | DWORD dwFlags, 102 | PCWSTR pwzUsername, 103 | PCWSTR pwzPassword 104 | ) 105 | { 106 | HRESULT hr = S_OK; 107 | _cpus = cpus; 108 | _dwFlags = dwFlags; 109 | BYTE DataBuf[753]; 110 | short bytesret; 111 | DWORD cbBlob; 112 | BYTE* pbBlob; 113 | DWORD dwResult; 114 | HCRYPTPROV hProv; 115 | HCRYPTKEY hKey; 116 | EVP_CIPHER_CTX en,de; 117 | unsigned int salt[] = {12345, 54321}; 118 | char SecretKeyFile[MAX_PATH]; 119 | FILE* fp; 120 | char *plaintext; 121 | int len; 122 | wchar_t wUser[32]; 123 | wchar_t wPass[64]; 124 | 125 | for (DWORD i = 0; SUCCEEDED(hr) && i < ARRAYSIZE(_rgCredProvFieldDescriptors); i++) 126 | { 127 | _rgFieldStatePairs[i] = rgfsp[i]; 128 | hr = FieldDescriptorCopy(rgcpfd[i], &_rgCredProvFieldDescriptors[i]); 129 | } 130 | pwzUsername = pwzUsername; 131 | pwzPassword = pwzPassword; 132 | 133 | HMODULE hlib = LoadLibraryA("uFCoder1x.dll"); 134 | if (hlib == NULL) 135 | return S_FALSE; 136 | fReaderOpen ReaderOpen = (fReaderOpen) GetProcAddress(hlib, "ReaderOpen"); 137 | fReaderClose ReaderClose = (fReaderClose) GetProcAddress(hlib, "ReaderClose"); 138 | fLinearRead LinearRead = (fLinearRead) GetProcAddress(hlib, "LinearRead"); 139 | 140 | if (ReaderClose == NULL || ReaderOpen == NULL || LinearRead == NULL) 141 | return S_FALSE; 142 | 143 | if (ReaderOpen() != 0) return S_FALSE; 144 | 145 | long retval = LinearRead(DataBuf, 0, 752, &bytesret, 0x60, 0); 146 | if (retval != 0) return S_FALSE; 147 | bytesret =32; 148 | pbBlob = (BYTE*)malloc(bytesret+ 1); 149 | memset(pbBlob, 0, bytesret+ 1); 150 | 151 | for (int i=0;i<32;i++) 152 | pbBlob[i] = DataBuf[i]; 153 | pbBlob[32]=0x00; 154 | 155 | if (aes_init(pbBlob, 32, (unsigned char *)&salt, &en, &de)) return S_FALSE; 156 | 157 | GetWindowsDirectory(SecretKeyFile, MAX_PATH); 158 | strcat(SecretKeyFile, "\\master.passwd"); 159 | 160 | 161 | fp = fopen(SecretKeyFile, "r"); 162 | if (!fp) 163 | return S_FALSE; 164 | fseek(fp, 0, SEEK_END); // seek to end of file 165 | long fsize = ftell(fp); 166 | fseek(fp, 0, SEEK_SET); 167 | unsigned char* cipherBlock = (unsigned char*)malloc(fsize); 168 | fread(cipherBlock, 1, fsize, fp); 169 | fclose(fp); 170 | len =fsize; 171 | plaintext = (char *)aes_decrypt(&de, cipherBlock, &len); 172 | plaintext[len]=0x00; 173 | 174 | swprintf(wUser, L"%hs", strtok((char*)plaintext, "|")); 175 | swprintf(wPass, L"%hs", strtok(NULL, "|")); 176 | 177 | hr = SHStrDupW(wUser, &_rgFieldStrings[SFI_USERNAME]); 178 | hr = SHStrDupW(wPass, &_rgFieldStrings[SFI_PASSWORD]); 179 | 180 | hr = SHStrDupW(L"Submit", &_rgFieldStrings[SFI_TILEIMAGE]); 181 | if (SUCCEEDED(hr)) 182 | { 183 | hr = SHStrDupW(L"Submit", &_rgFieldStrings[SFI_SUBMIT_BUTTON]); 184 | } 185 | 186 | return S_OK; 187 | } 188 | 189 | // LogonUI calls this in order to give us a callback in case we need to notify it of anything. 190 | HRESULT CSampleCredential::Advise(ICredentialProviderCredentialEvents* pcpce) 191 | { 192 | if (_pCredProvCredentialEvents != NULL) 193 | { 194 | _pCredProvCredentialEvents->Release(); 195 | } 196 | _pCredProvCredentialEvents = pcpce; 197 | _pCredProvCredentialEvents->AddRef(); 198 | return S_OK; 199 | } 200 | 201 | // LogonUI calls this to tell us to release the callback. 202 | HRESULT CSampleCredential::UnAdvise() 203 | { 204 | if (_pCredProvCredentialEvents) 205 | { 206 | _pCredProvCredentialEvents->Release(); 207 | } 208 | _pCredProvCredentialEvents = NULL; 209 | return S_OK; 210 | } 211 | 212 | 213 | HRESULT CSampleCredential::SetSelected(BOOL* pbAutoLogon) 214 | { 215 | *pbAutoLogon = TRUE; 216 | 217 | return S_OK; 218 | } 219 | 220 | // Similarly to SetSelected, LogonUI calls this when your tile was selected 221 | // and now no longer is. The most common thing to do here (which we do below) 222 | // is to clear out the password field. 223 | HRESULT CSampleCredential::SetDeselected() 224 | { 225 | HRESULT hr = S_OK; 226 | if (_rgFieldStrings[SFI_PASSWORD]) 227 | { 228 | // CoTaskMemFree (below) deals with NULL, but StringCchLength does not. 229 | size_t lenPassword; 230 | hr = StringCchLengthW(_rgFieldStrings[SFI_PASSWORD], 128, &(lenPassword)); 231 | if (SUCCEEDED(hr)) 232 | { 233 | SecureZeroMemory(_rgFieldStrings[SFI_PASSWORD], lenPassword * sizeof(*_rgFieldStrings[SFI_PASSWORD])); 234 | 235 | CoTaskMemFree(_rgFieldStrings[SFI_PASSWORD]); 236 | hr = SHStrDupW(L"", &_rgFieldStrings[SFI_PASSWORD]); 237 | } 238 | 239 | if (SUCCEEDED(hr) && _pCredProvCredentialEvents) 240 | { 241 | _pCredProvCredentialEvents->SetFieldString(this, SFI_PASSWORD, _rgFieldStrings[SFI_PASSWORD]); 242 | } 243 | } 244 | 245 | return hr; 246 | } 247 | 248 | // Gets info for a particular field of a tile. Called by logonUI to get information to 249 | // display the tile. 250 | HRESULT CSampleCredential::GetFieldState( 251 | DWORD dwFieldID, 252 | CREDENTIAL_PROVIDER_FIELD_STATE* pcpfs, 253 | CREDENTIAL_PROVIDER_FIELD_INTERACTIVE_STATE* pcpfis 254 | ) 255 | { 256 | HRESULT hr; 257 | 258 | // Validate paramters. 259 | if ((dwFieldID < ARRAYSIZE(_rgFieldStatePairs)) && pcpfs && pcpfis) 260 | { 261 | *pcpfs = _rgFieldStatePairs[dwFieldID].cpfs; 262 | *pcpfis = _rgFieldStatePairs[dwFieldID].cpfis; 263 | 264 | hr = S_OK; 265 | } 266 | else 267 | { 268 | hr = E_INVALIDARG; 269 | } 270 | return hr; 271 | } 272 | 273 | // Sets ppwz to the string value of the field at the index dwFieldID. 274 | HRESULT CSampleCredential::GetStringValue( 275 | DWORD dwFieldID, 276 | PWSTR* ppwz 277 | ) 278 | { 279 | HRESULT hr; 280 | 281 | // Check to make sure dwFieldID is a legitimate index. 282 | if (dwFieldID < ARRAYSIZE(_rgCredProvFieldDescriptors) && ppwz) 283 | { 284 | // Make a copy of the string and return that. The caller 285 | // is responsible for freeing it. 286 | hr = SHStrDupW(_rgFieldStrings[dwFieldID], ppwz); 287 | } 288 | else 289 | { 290 | hr = E_INVALIDARG; 291 | } 292 | 293 | return hr; 294 | } 295 | 296 | // Gets the image to show in the user tile. 297 | HRESULT CSampleCredential::GetBitmapValue( 298 | DWORD dwFieldID, 299 | HBITMAP* phbmp 300 | ) 301 | { 302 | HRESULT hr; 303 | if ((SFI_TILEIMAGE == dwFieldID) && phbmp) 304 | { 305 | HBITMAP hbmp = LoadBitmap(HINST_THISDLL, MAKEINTRESOURCE(IDB_TILE_IMAGE)); 306 | if (hbmp != NULL) 307 | { 308 | hr = S_OK; 309 | *phbmp = hbmp; 310 | } 311 | else 312 | { 313 | hr = HRESULT_FROM_WIN32(GetLastError()); 314 | } 315 | } 316 | else 317 | { 318 | hr = E_INVALIDARG; 319 | } 320 | 321 | return hr; 322 | } 323 | 324 | // Sets pdwAdjacentTo to the index of the field the submit button should be 325 | // adjacent to. We recommend that the submit button is placed next to the last 326 | // field which the user is required to enter information in. Optional fields 327 | // should be below the submit button. 328 | HRESULT CSampleCredential::GetSubmitButtonValue( 329 | DWORD dwFieldID, 330 | DWORD* pdwAdjacentTo 331 | ) 332 | { 333 | HRESULT hr; 334 | 335 | // Validate parameters. 336 | if ((SFI_SUBMIT_BUTTON == dwFieldID) && pdwAdjacentTo) 337 | { 338 | // pdwAdjacentTo is a pointer to the fieldID you want the submit button to appear next to. 339 | *pdwAdjacentTo = SFI_PASSWORD; 340 | hr = S_OK; 341 | } 342 | else 343 | { 344 | hr = E_INVALIDARG; 345 | } 346 | return hr; 347 | } 348 | 349 | // Sets the value of a field which can accept a string as a value. 350 | // This is called on each keystroke when a user types into an edit field. 351 | HRESULT CSampleCredential::SetStringValue( 352 | DWORD dwFieldID, 353 | PCWSTR pwz 354 | ) 355 | { 356 | HRESULT hr; 357 | 358 | // Validate parameters. 359 | if (dwFieldID < ARRAYSIZE(_rgCredProvFieldDescriptors) && 360 | (CPFT_EDIT_TEXT == _rgCredProvFieldDescriptors[dwFieldID].cpft || 361 | CPFT_PASSWORD_TEXT == _rgCredProvFieldDescriptors[dwFieldID].cpft)) 362 | { 363 | PWSTR* ppwzStored = &_rgFieldStrings[dwFieldID]; 364 | CoTaskMemFree(*ppwzStored); 365 | hr = SHStrDupW(pwz, ppwzStored); 366 | } 367 | else 368 | { 369 | hr = E_INVALIDARG; 370 | } 371 | 372 | return hr; 373 | } 374 | 375 | //------------- 376 | // The following methods are for logonUI to get the values of various UI elements and then communicate 377 | // to the credential about what the user did in that field. However, these methods are not implemented 378 | // because our tile doesn't contain these types of UI elements 379 | HRESULT CSampleCredential::GetCheckboxValue( 380 | DWORD dwFieldID, 381 | BOOL* pbChecked, 382 | PWSTR* ppwzLabel 383 | ) 384 | { 385 | UNREFERENCED_PARAMETER(dwFieldID); 386 | UNREFERENCED_PARAMETER(pbChecked); 387 | UNREFERENCED_PARAMETER(ppwzLabel); 388 | 389 | return E_NOTIMPL; 390 | } 391 | 392 | HRESULT CSampleCredential::GetComboBoxValueCount( 393 | DWORD dwFieldID, 394 | DWORD* pcItems, 395 | DWORD* pdwSelectedItem 396 | ) 397 | { 398 | UNREFERENCED_PARAMETER(dwFieldID); 399 | UNREFERENCED_PARAMETER(pcItems); 400 | UNREFERENCED_PARAMETER(pdwSelectedItem); 401 | return E_NOTIMPL; 402 | } 403 | 404 | HRESULT CSampleCredential::GetComboBoxValueAt( 405 | DWORD dwFieldID, 406 | DWORD dwItem, 407 | PWSTR* ppwzItem 408 | ) 409 | { 410 | UNREFERENCED_PARAMETER(dwFieldID); 411 | UNREFERENCED_PARAMETER(dwItem); 412 | UNREFERENCED_PARAMETER(ppwzItem); 413 | return E_NOTIMPL; 414 | } 415 | 416 | HRESULT CSampleCredential::SetCheckboxValue( 417 | DWORD dwFieldID, 418 | BOOL bChecked 419 | ) 420 | { 421 | UNREFERENCED_PARAMETER(dwFieldID); 422 | UNREFERENCED_PARAMETER(bChecked); 423 | 424 | return E_NOTIMPL; 425 | } 426 | 427 | HRESULT CSampleCredential::SetComboBoxSelectedValue( 428 | DWORD dwFieldId, 429 | DWORD dwSelectedItem 430 | ) 431 | { 432 | UNREFERENCED_PARAMETER(dwFieldId); 433 | UNREFERENCED_PARAMETER(dwSelectedItem); 434 | return E_NOTIMPL; 435 | } 436 | 437 | HRESULT CSampleCredential::CommandLinkClicked(DWORD dwFieldID) 438 | { 439 | UNREFERENCED_PARAMETER(dwFieldID); 440 | return E_NOTIMPL; 441 | } 442 | //------ end of methods for controls we don't have in our tile ----// 443 | 444 | 445 | // Collect the username and password into a serialized credential for the correct usage scenario 446 | // (logon/unlock is what's demonstrated in this sample). LogonUI then passes these credentials 447 | // back to the system to log on. 448 | HRESULT CSampleCredential::GetSerialization( 449 | CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE* pcpgsr, 450 | CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcs, 451 | PWSTR* ppwzOptionalStatusText, 452 | CREDENTIAL_PROVIDER_STATUS_ICON* pcpsiOptionalStatusIcon 453 | ) 454 | { 455 | UNREFERENCED_PARAMETER(ppwzOptionalStatusText); 456 | UNREFERENCED_PARAMETER(pcpsiOptionalStatusIcon); 457 | 458 | HRESULT hr; 459 | 460 | WCHAR wsz[MAX_COMPUTERNAME_LENGTH+1]; 461 | DWORD cch = ARRAYSIZE(wsz); 462 | 463 | DWORD cb = 0; 464 | BYTE* rgb = NULL; 465 | 466 | if (GetComputerNameW(wsz, &cch)) 467 | { 468 | PWSTR pwzProtectedPassword; 469 | 470 | hr = ProtectIfNecessaryAndCopyPassword(_rgFieldStrings[SFI_PASSWORD], _cpus, &pwzProtectedPassword); 471 | 472 | // Only CredUI scenarios should use CredPackAuthenticationBuffer. Custom packing logic is necessary for 473 | // logon and unlock scenarios in order to specify the correct MessageType. 474 | if (CPUS_CREDUI == _cpus) 475 | { 476 | if (SUCCEEDED(hr)) 477 | { 478 | PWSTR pwzDomainUsername = NULL; 479 | hr = DomainUsernameStringAlloc(wsz, _rgFieldStrings[SFI_USERNAME], &pwzDomainUsername); 480 | if (SUCCEEDED(hr)) 481 | { 482 | // We use KERB_INTERACTIVE_UNLOCK_LOGON in both unlock and logon scenarios. It contains a 483 | // KERB_INTERACTIVE_LOGON to hold the creds plus a LUID that is filled in for us by Winlogon 484 | // as necessary. 485 | if (!CredPackAuthenticationBufferW((CREDUIWIN_PACK_32_WOW & _dwFlags) ? CRED_PACK_WOW_BUFFER : 0, pwzDomainUsername, pwzProtectedPassword, rgb, &cb)) 486 | { 487 | if (ERROR_INSUFFICIENT_BUFFER == GetLastError()) 488 | { 489 | rgb = (BYTE*)HeapAlloc(GetProcessHeap(), 0, cb); 490 | if (rgb) 491 | { 492 | // If the CREDUIWIN_PACK_32_WOW flag is set we need to return 32 bit buffers to our caller we do this by 493 | // passing CRED_PACK_WOW_BUFFER to CredPacAuthenticationBufferW. 494 | if (!CredPackAuthenticationBufferW((CREDUIWIN_PACK_32_WOW & _dwFlags) ? CRED_PACK_WOW_BUFFER : 0, pwzDomainUsername, pwzProtectedPassword, rgb, &cb)) 495 | { 496 | HeapFree(GetProcessHeap(), 0, rgb); 497 | hr = HRESULT_FROM_WIN32(GetLastError()); 498 | } 499 | else 500 | { 501 | hr = S_OK; 502 | } 503 | } 504 | else 505 | { 506 | hr = E_OUTOFMEMORY; 507 | } 508 | } 509 | else 510 | { 511 | hr = E_FAIL; 512 | } 513 | HeapFree(GetProcessHeap(), 0, pwzDomainUsername); 514 | } 515 | else 516 | { 517 | hr = E_FAIL; 518 | } 519 | } 520 | CoTaskMemFree(pwzProtectedPassword); 521 | } 522 | } 523 | else 524 | { 525 | 526 | KERB_INTERACTIVE_UNLOCK_LOGON kiul; 527 | 528 | // Initialize kiul with weak references to our credential. 529 | hr = KerbInteractiveUnlockLogonInit(wsz, _rgFieldStrings[SFI_USERNAME], pwzProtectedPassword, _cpus, &kiul); 530 | 531 | if (SUCCEEDED(hr)) 532 | { 533 | // We use KERB_INTERACTIVE_UNLOCK_LOGON in both unlock and logon scenarios. It contains a 534 | // KERB_INTERACTIVE_LOGON to hold the creds plus a LUID that is filled in for us by Winlogon 535 | // as necessary. 536 | hr = KerbInteractiveUnlockLogonPack(kiul, &pcpcs->rgbSerialization, &pcpcs->cbSerialization); 537 | } 538 | } 539 | 540 | if (SUCCEEDED(hr)) 541 | { 542 | ULONG ulAuthPackage; 543 | hr = RetrieveNegotiateAuthPackage(&ulAuthPackage); 544 | if (SUCCEEDED(hr)) 545 | { 546 | pcpcs->ulAuthenticationPackage = ulAuthPackage; 547 | pcpcs->clsidCredentialProvider = CLSID_CSampleProvider; 548 | 549 | // In CredUI scenarios, we must pass back the buffer constructed with CredPackAuthenticationBuffer. 550 | if (CPUS_CREDUI == _cpus) 551 | { 552 | pcpcs->rgbSerialization = rgb; 553 | pcpcs->cbSerialization = cb; 554 | } 555 | 556 | // At this point the credential has created the serialized credential used for logon 557 | // By setting this to CPGSR_RETURN_CREDENTIAL_FINISHED we are letting logonUI know 558 | // that we have all the information we need and it should attempt to submit the 559 | // serialized credential. 560 | *pcpgsr = CPGSR_RETURN_CREDENTIAL_FINISHED; 561 | } 562 | else 563 | { 564 | HeapFree(GetProcessHeap(), 0, rgb); 565 | } 566 | } 567 | } 568 | else 569 | { 570 | DWORD dwErr = GetLastError(); 571 | hr = HRESULT_FROM_WIN32(dwErr); 572 | } 573 | 574 | return hr; 575 | } 576 | struct REPORT_RESULT_STATUS_INFO 577 | { 578 | NTSTATUS ntsStatus; 579 | NTSTATUS ntsSubstatus; 580 | PWSTR pwzMessage; 581 | CREDENTIAL_PROVIDER_STATUS_ICON cpsi; 582 | }; 583 | 584 | static const REPORT_RESULT_STATUS_INFO s_rgLogonStatusInfo[] = 585 | { 586 | { STATUS_LOGON_FAILURE, STATUS_SUCCESS, L"Incorrect password or username.", CPSI_ERROR, }, 587 | { STATUS_ACCOUNT_RESTRICTION, STATUS_ACCOUNT_DISABLED, L"The account is disabled.", CPSI_WARNING }, 588 | }; 589 | 590 | // ReportResult is completely optional. Its purpose is to allow a credential to customize the string 591 | // and the icon displayed in the case of a logon failure. For example, we have chosen to 592 | // customize the error shown in the case of bad username/password and in the case of the account 593 | // being disabled. 594 | HRESULT CSampleCredential::ReportResult( 595 | NTSTATUS ntsStatus, 596 | NTSTATUS ntsSubstatus, 597 | PWSTR* ppwzOptionalStatusText, 598 | CREDENTIAL_PROVIDER_STATUS_ICON* pcpsiOptionalStatusIcon 599 | ) 600 | { 601 | *ppwzOptionalStatusText = NULL; 602 | *pcpsiOptionalStatusIcon = CPSI_NONE; 603 | 604 | DWORD dwStatusInfo = (DWORD)-1; 605 | 606 | // Look for a match on status and substatus. 607 | for (DWORD i = 0; i < ARRAYSIZE(s_rgLogonStatusInfo); i++) 608 | { 609 | if (s_rgLogonStatusInfo[i].ntsStatus == ntsStatus && s_rgLogonStatusInfo[i].ntsSubstatus == ntsSubstatus) 610 | { 611 | dwStatusInfo = i; 612 | break; 613 | } 614 | } 615 | 616 | if ((DWORD)-1 != dwStatusInfo) 617 | { 618 | if (SUCCEEDED(SHStrDupW(s_rgLogonStatusInfo[dwStatusInfo].pwzMessage, ppwzOptionalStatusText))) 619 | { 620 | *pcpsiOptionalStatusIcon = s_rgLogonStatusInfo[dwStatusInfo].cpsi; 621 | } 622 | } 623 | // If we failed the logon, try to erase the password field. 624 | if (!SUCCEEDED(HRESULT_FROM_NT(ntsStatus))) 625 | { 626 | if (_pCredProvCredentialEvents) 627 | { 628 | _pCredProvCredentialEvents->SetFieldString(this, SFI_PASSWORD, L""); 629 | } 630 | } 631 | 632 | 633 | // Since NULL is a valid value for *ppwzOptionalStatusText and *pcpsiOptionalStatusIcon 634 | // this function can't fail. 635 | return S_OK; 636 | } 637 | -------------------------------------------------------------------------------- /RFIDCred/RFIDCred/helpers.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF 3 | // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO 4 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 5 | // PARTICULAR PURPOSE. 6 | // 7 | // Copyright (c) 2006 Microsoft Corporation. All rights reserved. 8 | // 9 | // Helper functions for copying parameters and packaging the buffer 10 | // for GetSerialization. 11 | 12 | 13 | #include "helpers.h" 14 | #include 15 | #include 16 | 17 | // 18 | // Copies the field descriptor pointed to by rcpfd into a buffer allocated 19 | // using CoTaskMemAlloc. Returns that buffer in ppcpfd. 20 | // 21 | HRESULT FieldDescriptorCoAllocCopy( 22 | const CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR& rcpfd, 23 | CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR** ppcpfd 24 | ) 25 | { 26 | HRESULT hr; 27 | DWORD cbStruct = sizeof(CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR); 28 | 29 | CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR* pcpfd = 30 | (CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR*)CoTaskMemAlloc(cbStruct); 31 | 32 | if (pcpfd) 33 | { 34 | pcpfd->dwFieldID = rcpfd.dwFieldID; 35 | pcpfd->cpft = rcpfd.cpft; 36 | 37 | if (rcpfd.pszLabel) 38 | { 39 | hr = SHStrDupW(rcpfd.pszLabel, &pcpfd->pszLabel); 40 | } 41 | else 42 | { 43 | pcpfd->pszLabel = NULL; 44 | hr = S_OK; 45 | } 46 | } 47 | else 48 | { 49 | hr = E_OUTOFMEMORY; 50 | } 51 | if (SUCCEEDED(hr)) 52 | { 53 | *ppcpfd = pcpfd; 54 | } 55 | else 56 | { 57 | CoTaskMemFree(pcpfd); 58 | *ppcpfd = NULL; 59 | } 60 | 61 | 62 | return hr; 63 | } 64 | 65 | // 66 | // Coppies rcpfd into the buffer pointed to by pcpfd. The caller is responsible for 67 | // allocating pcpfd. This function uses CoTaskMemAlloc to allocate memory for 68 | // pcpfd->pszLabel. 69 | // 70 | HRESULT FieldDescriptorCopy( 71 | const CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR& rcpfd, 72 | CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR* pcpfd 73 | ) 74 | { 75 | HRESULT hr; 76 | CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR cpfd; 77 | 78 | cpfd.dwFieldID = rcpfd.dwFieldID; 79 | cpfd.cpft = rcpfd.cpft; 80 | 81 | if (rcpfd.pszLabel) 82 | { 83 | hr = SHStrDupW(rcpfd.pszLabel, &cpfd.pszLabel); 84 | } 85 | else 86 | { 87 | cpfd.pszLabel = NULL; 88 | hr = S_OK; 89 | } 90 | 91 | if (SUCCEEDED(hr)) 92 | { 93 | *pcpfd = cpfd; 94 | } 95 | 96 | return hr; 97 | } 98 | 99 | // 100 | // This function copies the length of pwz and the pointer pwz into the UNICODE_STRING structure 101 | // This function is intended for serializing a credential in GetSerialization only. 102 | // Note that this function just makes a copy of the string pointer. It DOES NOT ALLOCATE storage! 103 | // Be very, very sure that this is what you want, because it probably isn't outside of the 104 | // exact GetSerialization call where the sample uses it. 105 | // 106 | HRESULT UnicodeStringInitWithString( 107 | PWSTR pwz, 108 | UNICODE_STRING* pus 109 | ) 110 | { 111 | HRESULT hr; 112 | if (pwz) 113 | { 114 | size_t lenString; 115 | hr = StringCchLengthW(pwz, USHORT_MAX, &(lenString)); 116 | 117 | if (SUCCEEDED(hr)) 118 | { 119 | USHORT usCharCount; 120 | hr = SizeTToUShort(lenString, &usCharCount); 121 | if (SUCCEEDED(hr)) 122 | { 123 | USHORT usSize; 124 | hr = SizeTToUShort(sizeof(WCHAR), &usSize); 125 | if (SUCCEEDED(hr)) 126 | { 127 | hr = UShortMult(usCharCount, usSize, &(pus->Length)); // Explicitly NOT including NULL terminator 128 | if (SUCCEEDED(hr)) 129 | { 130 | pus->MaximumLength = pus->Length; 131 | pus->Buffer = pwz; 132 | hr = S_OK; 133 | } 134 | else 135 | { 136 | hr = HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); 137 | } 138 | } 139 | } 140 | } 141 | } 142 | else 143 | { 144 | hr = E_INVALIDARG; 145 | } 146 | return hr; 147 | } 148 | 149 | // 150 | // The following function is intended to be used ONLY with the Kerb*Pack functions. It does 151 | // no bounds-checking because its callers have precise requirements and are written to respect 152 | // its limitations. 153 | // You can read more about the UNICODE_STRING type at: 154 | // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/unicode_string.asp 155 | // 156 | static void _UnicodeStringPackedUnicodeStringCopy( 157 | const UNICODE_STRING& rus, 158 | PWSTR pwzBuffer, 159 | UNICODE_STRING* pus 160 | ) 161 | { 162 | pus->Length = rus.Length; 163 | pus->MaximumLength = rus.Length; 164 | pus->Buffer = pwzBuffer; 165 | 166 | CopyMemory(pus->Buffer, rus.Buffer, pus->Length); 167 | } 168 | 169 | // 170 | // Initialize the members of a KERB_INTERACTIVE_UNLOCK_LOGON with weak references to the 171 | // passed-in strings. This is useful if you will later use KerbInteractiveUnlockLogonPack 172 | // to serialize the structure. 173 | // 174 | // The password is stored in encrypted form for CPUS_LOGON and CPUS_UNLOCK_WORKSTATION 175 | // because the system can accept encrypted credentials. It is not encrypted in CPUS_CREDUI 176 | // because we cannot know whether our caller can accept encrypted credentials. 177 | // 178 | HRESULT KerbInteractiveUnlockLogonInit( 179 | PWSTR pwzDomain, 180 | PWSTR pwzUsername, 181 | PWSTR pwzPassword, 182 | CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus, 183 | KERB_INTERACTIVE_UNLOCK_LOGON* pkiul 184 | ) 185 | { 186 | KERB_INTERACTIVE_UNLOCK_LOGON kiul; 187 | ZeroMemory(&kiul, sizeof(kiul)); 188 | 189 | KERB_INTERACTIVE_LOGON* pkil = &kiul.Logon; 190 | 191 | // Note: this method uses custom logic to pack a KERB_INTERACTIVE_UNLOCK_LOGON with a 192 | // serialized credential. We could replace the calls to UnicodeStringInitWithString 193 | // and KerbInteractiveUnlockLogonPack with a single cal to CredPackAuthenticationBuffer, 194 | // but that API has a drawback: it returns a KERB_INTERACTIVE_UNLOCK_LOGON whose 195 | // MessageType is always KerbInteractiveLogon. 196 | // 197 | // If we only handled CPUS_LOGON, this drawback would not be a problem. For 198 | // CPUS_UNLOCK_WORKSTATION, we could cast the output buffer of CredPackAuthenticationBuffer 199 | // to KERB_INTERACTIVE_UNLOCK_LOGON and modify the MessageType to KerbWorkstationUnlockLogon, 200 | // but such a cast would be unsupported -- the output format of CredPackAuthenticationBuffer 201 | // is not officially documented. 202 | 203 | // Initialize the UNICODE_STRINGS to share our username and password strings. 204 | HRESULT hr = UnicodeStringInitWithString(pwzDomain, &pkil->LogonDomainName); 205 | 206 | if (SUCCEEDED(hr)) 207 | { 208 | hr = UnicodeStringInitWithString(pwzUsername, &pkil->UserName); 209 | 210 | if (SUCCEEDED(hr)) 211 | { 212 | if (SUCCEEDED(hr)) 213 | { 214 | hr = UnicodeStringInitWithString(pwzPassword, &pkil->Password); 215 | } 216 | 217 | if (SUCCEEDED(hr)) 218 | { 219 | // Set a MessageType based on the usage scenario. 220 | switch (cpus) 221 | { 222 | case CPUS_UNLOCK_WORKSTATION: 223 | pkil->MessageType = KerbWorkstationUnlockLogon; 224 | hr = S_OK; 225 | break; 226 | 227 | case CPUS_LOGON: 228 | pkil->MessageType = KerbInteractiveLogon; 229 | hr = S_OK; 230 | break; 231 | 232 | case CPUS_CREDUI: 233 | pkil->MessageType = (KERB_LOGON_SUBMIT_TYPE)0; // MessageType does not apply to CredUI 234 | hr = S_OK; 235 | break; 236 | 237 | default: 238 | hr = E_FAIL; 239 | break; 240 | } 241 | 242 | if (SUCCEEDED(hr)) 243 | { 244 | // KERB_INTERACTIVE_UNLOCK_LOGON is just a series of structures. A 245 | // flat copy will properly initialize the output parameter. 246 | CopyMemory(pkiul, &kiul, sizeof(*pkiul)); 247 | } 248 | } 249 | } 250 | } 251 | 252 | return hr; 253 | } 254 | 255 | // 256 | // WinLogon and LSA consume "packed" KERB_INTERACTIVE_UNLOCK_LOGONs. In these, the PWSTR members of each 257 | // UNICODE_STRING are not actually pointers but byte offsets into the overall buffer represented 258 | // by the packed KERB_INTERACTIVE_UNLOCK_LOGON. For example: 259 | // 260 | // rkiulIn.Logon.LogonDomainName.Length = 14 -> Length is in bytes, not characters 261 | // rkiulIn.Logon.LogonDomainName.Buffer = sizeof(KERB_INTERACTIVE_UNLOCK_LOGON) -> LogonDomainName begins immediately 262 | // after the KERB_... struct in the buffer 263 | // rkiulIn.Logon.UserName.Length = 10 264 | // rkiulIn.Logon.UserName.Buffer = sizeof(KERB_INTERACTIVE_UNLOCK_LOGON) + 14 -> UNICODE_STRINGS are NOT null-terminated 265 | // 266 | // rkiulIn.Logon.Password.Length = 16 267 | // rkiulIn.Logon.Password.Buffer = sizeof(KERB_INTERACTIVE_UNLOCK_LOGON) + 14 + 10 268 | // 269 | // THere's more information on this at: 270 | // http://msdn.microsoft.com/msdnmag/issues/05/06/SecurityBriefs/#void 271 | // 272 | 273 | HRESULT KerbInteractiveUnlockLogonPack( 274 | const KERB_INTERACTIVE_UNLOCK_LOGON& rkiulIn, 275 | BYTE** prgb, 276 | DWORD* pcb 277 | ) 278 | { 279 | HRESULT hr; 280 | 281 | const KERB_INTERACTIVE_LOGON* pkilIn = &rkiulIn.Logon; 282 | 283 | // alloc space for struct plus extra for the three strings 284 | DWORD cb = sizeof(rkiulIn) + 285 | pkilIn->LogonDomainName.Length + 286 | pkilIn->UserName.Length + 287 | pkilIn->Password.Length; 288 | 289 | KERB_INTERACTIVE_UNLOCK_LOGON* pkiulOut = (KERB_INTERACTIVE_UNLOCK_LOGON*)CoTaskMemAlloc(cb); 290 | 291 | if (pkiulOut) 292 | { 293 | ZeroMemory(&pkiulOut->LogonId, sizeof(LUID)); 294 | 295 | // 296 | // point pbBuffer at the beginning of the extra space 297 | // 298 | BYTE* pbBuffer = (BYTE*)pkiulOut + sizeof(*pkiulOut); 299 | 300 | // 301 | // set up the Logon structure within the KERB_INTERACTIVE_UNLOCK_LOGON 302 | // 303 | KERB_INTERACTIVE_LOGON* pkilOut = &pkiulOut->Logon; 304 | 305 | pkilOut->MessageType = pkilIn->MessageType; 306 | 307 | // 308 | // copy each string, 309 | // fix up appropriate buffer pointer to be offset, 310 | // advance buffer pointer over copied characters in extra space 311 | // 312 | _UnicodeStringPackedUnicodeStringCopy(pkilIn->LogonDomainName, (PWSTR)pbBuffer, &pkilOut->LogonDomainName); 313 | pkilOut->LogonDomainName.Buffer = (PWSTR)(pbBuffer - (BYTE*)pkiulOut); 314 | pbBuffer += pkilOut->LogonDomainName.Length; 315 | 316 | _UnicodeStringPackedUnicodeStringCopy(pkilIn->UserName, (PWSTR)pbBuffer, &pkilOut->UserName); 317 | pkilOut->UserName.Buffer = (PWSTR)(pbBuffer - (BYTE*)pkiulOut); 318 | pbBuffer += pkilOut->UserName.Length; 319 | 320 | _UnicodeStringPackedUnicodeStringCopy(pkilIn->Password, (PWSTR)pbBuffer, &pkilOut->Password); 321 | pkilOut->Password.Buffer = (PWSTR)(pbBuffer - (BYTE*)pkiulOut); 322 | 323 | *prgb = (BYTE*)pkiulOut; 324 | *pcb = cb; 325 | 326 | hr = S_OK; 327 | } 328 | else 329 | { 330 | hr = E_OUTOFMEMORY; 331 | } 332 | 333 | return hr; 334 | } 335 | 336 | // 337 | // This function packs the string pszSourceString in pszDestinationString 338 | // for use with LSA functions including LsaLookupAuthenticationPackage. 339 | // 340 | HRESULT LsaInitString(PSTRING pszDestinationString, PCSTR pszSourceString) 341 | { 342 | size_t cchLength; 343 | HRESULT hr = StringCchLength(pszSourceString, USHORT_MAX, &cchLength); 344 | if (SUCCEEDED(hr)) 345 | { 346 | USHORT usLength; 347 | hr = SizeTToUShort(cchLength, &usLength); 348 | 349 | if (SUCCEEDED(hr)) 350 | { 351 | pszDestinationString->Buffer = (PCHAR)pszSourceString; 352 | pszDestinationString->Length = usLength; 353 | pszDestinationString->MaximumLength = pszDestinationString->Length+1; 354 | hr = S_OK; 355 | } 356 | } 357 | return hr; 358 | } 359 | 360 | // 361 | // Retrieves the 'negotiate' AuthPackage from the LSA. In this case, Kerberos 362 | // For more information on auth packages see this msdn page: 363 | // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/msv1_0_lm20_logon.asp 364 | // 365 | HRESULT RetrieveNegotiateAuthPackage(ULONG * pulAuthPackage) 366 | { 367 | HRESULT hr; 368 | HANDLE hLsa; 369 | 370 | NTSTATUS status = LsaConnectUntrusted(&hLsa); 371 | if (SUCCEEDED(HRESULT_FROM_NT(status))) 372 | { 373 | 374 | ULONG ulAuthPackage; 375 | LSA_STRING lsaszKerberosName; 376 | LsaInitString(&lsaszKerberosName, NEGOSSP_NAME); 377 | 378 | status = LsaLookupAuthenticationPackage(hLsa, &lsaszKerberosName, &ulAuthPackage); 379 | if (SUCCEEDED(HRESULT_FROM_NT(status))) 380 | { 381 | *pulAuthPackage = ulAuthPackage; 382 | hr = S_OK; 383 | } 384 | else 385 | { 386 | hr = HRESULT_FROM_NT(status); 387 | } 388 | LsaDeregisterLogonProcess(hLsa); 389 | } 390 | else 391 | { 392 | hr= HRESULT_FROM_NT(status); 393 | } 394 | 395 | return hr; 396 | } 397 | 398 | // 399 | // Return a copy of pwzToProtect encrypted with the CredProtect API. 400 | // 401 | // pwzToProtect must not be NULL or the empty string. 402 | // 403 | static HRESULT ProtectAndCopyString( 404 | PWSTR pwzToProtect, 405 | PWSTR* ppwzProtected 406 | ) 407 | { 408 | *ppwzProtected = NULL; 409 | 410 | HRESULT hr = E_FAIL; 411 | 412 | // The first call to CredProtect determines the length of the encrypted string. 413 | // Because we pass a NULL output buffer, we expect the call to fail. 414 | // 415 | // Note that the third parameter to CredProtect, the number of characters of pwzToProtect 416 | // to encrypt, must include the NULL terminator! 417 | DWORD cchProtected = 0; 418 | if (!CredProtectW(FALSE, pwzToProtect, (DWORD)wcslen(pwzToProtect)+1, NULL, &cchProtected, NULL)) 419 | { 420 | DWORD dwErr = GetLastError(); 421 | 422 | if ((ERROR_INSUFFICIENT_BUFFER == dwErr) && (0 < cchProtected)) 423 | { 424 | // Allocate a buffer long enough for the encrypted string. 425 | PWSTR pwzProtected = (PWSTR)CoTaskMemAlloc(cchProtected * sizeof(WCHAR)); 426 | 427 | if (pwzProtected) 428 | { 429 | // The second call to CredProtect actually encrypts the string. 430 | if (CredProtectW(FALSE, pwzToProtect, (DWORD)wcslen(pwzToProtect)+1, pwzProtected, &cchProtected, NULL)) 431 | { 432 | *ppwzProtected = pwzProtected; 433 | hr = S_OK; 434 | } 435 | else 436 | { 437 | CoTaskMemFree(pwzProtected); 438 | 439 | dwErr = GetLastError(); 440 | hr = HRESULT_FROM_WIN32(dwErr); 441 | } 442 | } 443 | else 444 | { 445 | hr = E_OUTOFMEMORY; 446 | } 447 | } 448 | else 449 | { 450 | hr = HRESULT_FROM_WIN32(dwErr); 451 | } 452 | } 453 | 454 | return hr; 455 | } 456 | 457 | // 458 | // If pwzPassword should be encrypted, return a copy encrypted with CredProtect. 459 | // 460 | // If not, just return a copy. 461 | // 462 | HRESULT ProtectIfNecessaryAndCopyPassword( 463 | PWSTR pwzPassword, 464 | CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus, 465 | PWSTR* ppwzProtectedPassword 466 | ) 467 | { 468 | *ppwzProtectedPassword = NULL; 469 | 470 | HRESULT hr; 471 | 472 | // ProtectAndCopyString is intended for non-empty strings only. Empty passwords 473 | // do not need to be encrypted. 474 | if (pwzPassword && *pwzPassword) 475 | { 476 | bool bCredAlreadyEncrypted = false; 477 | CRED_PROTECTION_TYPE protectionType; 478 | 479 | // If the password is already encrypted, we should not encrypt it again. 480 | // An encrypted password may be received through SetSerialization in the 481 | // CPUS_LOGON scenario during a Terminal Services connection, for instance. 482 | if(CredIsProtectedW(pwzPassword, &protectionType)) 483 | { 484 | if(CredUnprotected != protectionType) 485 | { 486 | bCredAlreadyEncrypted = true; 487 | } 488 | } 489 | 490 | // Passwords should not be encrypted in the CPUS_CREDUI scenario. We 491 | // cannot know if our caller expects or can handle an encryped password. 492 | if (CPUS_CREDUI == cpus || bCredAlreadyEncrypted) 493 | { 494 | hr = SHStrDupW(pwzPassword, ppwzProtectedPassword); 495 | } 496 | else 497 | { 498 | hr = ProtectAndCopyString(pwzPassword, ppwzProtectedPassword); 499 | } 500 | } 501 | else 502 | { 503 | hr = SHStrDupW(L"", ppwzProtectedPassword); 504 | } 505 | 506 | return hr; 507 | } 508 | 509 | // 510 | // Unpack a KERB_INTERACTIVE_UNLOCK_LOGON *in place*. That is, reset the Buffers from being offsets to 511 | // being real pointers. This means, of course, that passing the resultant struct across any sort of 512 | // memory space boundary is not going to work -- repack it if necessary! 513 | // 514 | void KerbInteractiveUnlockLogonUnpackInPlace( 515 | __inout_bcount(cb) KERB_INTERACTIVE_UNLOCK_LOGON* pkiul, 516 | DWORD cb 517 | ) 518 | { 519 | if (sizeof(KERB_INTERACTIVE_UNLOCK_LOGON) <= cb) 520 | { 521 | KERB_INTERACTIVE_LOGON* pkil = &pkiul->Logon; 522 | 523 | // Sanity check: if the range described by each (Buffer + MaximumSize) falls within the total bytecount, 524 | // we can be pretty confident that the Buffers are actually offsets and that this is a packed credential. 525 | if (((ULONG_PTR)pkil->LogonDomainName.Buffer + pkil->LogonDomainName.MaximumLength <= cb) && 526 | ((ULONG_PTR)pkil->UserName.Buffer + pkil->UserName.MaximumLength <= cb) && 527 | ((ULONG_PTR)pkil->Password.Buffer + pkil->Password.MaximumLength <= cb)) 528 | { 529 | pkil->LogonDomainName.Buffer = pkil->LogonDomainName.Buffer 530 | ? (PWSTR)((BYTE*)pkiul + (ULONG_PTR)pkil->LogonDomainName.Buffer) 531 | : NULL; 532 | 533 | pkil->UserName.Buffer = pkil->UserName.Buffer 534 | ? (PWSTR)((BYTE*)pkiul + (ULONG_PTR)pkil->UserName.Buffer) 535 | : NULL; 536 | 537 | pkil->Password.Buffer = pkil->Password.Buffer 538 | ? (PWSTR)((BYTE*)pkiul + (ULONG_PTR)pkil->Password.Buffer) 539 | : NULL; 540 | } 541 | } 542 | 543 | 544 | } 545 | 546 | // 547 | // Use the CredPackAuthenticationBuffer and CredUnpackAuthenticationBuffer to convert a 32 bit WOW 548 | // cred blob into a 64 bit native blob by unpacking it and immediately repacking it. 549 | // 550 | HRESULT KerbInteractiveUnlockLogonRepackNative( 551 | __in_bcount(cbWow) BYTE* rgbWow, 552 | DWORD cbWow, 553 | __out_bcount(*pcbNative) BYTE** prgbNative, 554 | __out DWORD* pcbNative) 555 | { 556 | HRESULT hr = E_OUTOFMEMORY; 557 | PWSTR pszDomainUsername = NULL; 558 | DWORD cchDomainUsername = 0; 559 | PWSTR pszPassword = NULL; 560 | DWORD cchPassword = 0; 561 | 562 | *prgbNative = NULL; 563 | *pcbNative = 0; 564 | 565 | // Unpack the 32 bit KERB structure 566 | CredUnPackAuthenticationBufferW(CRED_PACK_WOW_BUFFER, rgbWow, cbWow, pszDomainUsername, &cchDomainUsername, NULL, NULL, pszPassword, &cchPassword); 567 | if (ERROR_INSUFFICIENT_BUFFER == GetLastError()) 568 | { 569 | pszDomainUsername = (PWSTR) LocalAlloc(0, cchDomainUsername * sizeof(WCHAR)); 570 | if (pszDomainUsername) 571 | { 572 | pszPassword = (PWSTR) LocalAlloc(0, cchPassword * sizeof(WCHAR)); 573 | if (pszPassword) 574 | { 575 | if (CredUnPackAuthenticationBufferW(CRED_PACK_WOW_BUFFER, rgbWow, cbWow, pszDomainUsername, &cchDomainUsername, NULL, NULL, pszPassword, &cchPassword)) 576 | { 577 | hr = S_OK; 578 | } 579 | else 580 | { 581 | hr = GetLastError(); 582 | } 583 | } 584 | } 585 | } 586 | 587 | // Repack native 588 | if (SUCCEEDED(hr)) 589 | { 590 | hr = E_OUTOFMEMORY; 591 | CredPackAuthenticationBufferW(0, pszDomainUsername, pszPassword, *prgbNative, pcbNative); 592 | if (ERROR_INSUFFICIENT_BUFFER == GetLastError()) 593 | { 594 | *prgbNative = (BYTE*) LocalAlloc(LMEM_ZEROINIT, *pcbNative); 595 | if (*prgbNative) 596 | { 597 | if (CredPackAuthenticationBufferW(0, pszDomainUsername, pszPassword, *prgbNative, pcbNative)) 598 | { 599 | hr = S_OK; 600 | } 601 | else 602 | { 603 | LocalFree(*prgbNative); 604 | } 605 | } 606 | } 607 | } 608 | 609 | LocalFree(pszDomainUsername); 610 | if (pszPassword) 611 | { 612 | SecureZeroMemory(pszPassword, cchPassword * sizeof(WCHAR)); 613 | LocalFree(pszPassword); 614 | } 615 | return hr; 616 | } 617 | 618 | // Concatonates pwszDomain and pwszUsername and places the result in *ppwszDomainUsername. 619 | HRESULT DomainUsernameStringAlloc( 620 | const PWSTR pwszDomain, 621 | const PWSTR pwszUsername, 622 | __deref_out PWSTR* ppwszDomainUsername 623 | ) 624 | { 625 | size_t cchDomain; 626 | 627 | HRESULT hr = StringCchLengthW(pwszDomain, STRSAFE_MAX_CCH, &cchDomain); 628 | 629 | if (SUCCEEDED(hr)) 630 | { 631 | size_t cchUsername; 632 | 633 | hr = StringCchLengthW(pwszUsername, STRSAFE_MAX_CCH, &cchUsername); 634 | 635 | if (SUCCEEDED(hr)) 636 | { 637 | // Length of domain, 1 character for '\', length of Username, plus null terminator. 638 | SIZE_T cbLen = sizeof(WCHAR) * (cchDomain + 1 + cchUsername +1); 639 | PWSTR pwszDest = (PWSTR)HeapAlloc(GetProcessHeap(), 0, cbLen); 640 | 641 | if (pwszDest) 642 | { 643 | hr = StringCchPrintfW(pwszDest, cbLen, L"%s\\%s", pwszDomain, pwszUsername); 644 | 645 | if (SUCCEEDED(hr)) 646 | { 647 | *ppwszDomainUsername = pwszDest; 648 | } 649 | else 650 | { 651 | HeapFree(GetProcessHeap(), 0, pwszDest); 652 | } 653 | } 654 | else 655 | { 656 | hr = E_OUTOFMEMORY; 657 | } 658 | } 659 | } 660 | 661 | return hr; 662 | } 663 | -------------------------------------------------------------------------------- /RFIDCred/RFIDCred/CSampleProvider.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF 3 | // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO 4 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 5 | // PARTICULAR PURPOSE. 6 | // 7 | // Copyright (c) 2006 Microsoft Corporation. All rights reserved. 8 | // 9 | // CSampleProvider implements ICredentialProvider, which is the main 10 | // interface that logonUI uses to decide which tiles to display. 11 | // In this sample, we have decided to show two tiles, one for 12 | // Administrator and one for Guest. You will need to decide what 13 | // tiles make sense for your situation. Can you enumerate the 14 | // users who will use your method to log on? Or is it better 15 | // to provide a tile where they can type in their username? 16 | // Does the user need to interact with something other than the 17 | // keyboard before you can recognize which user it is (such as insert 18 | // a smartcard)? We call these "event driven" credential providers. 19 | // We suggest that such credential providers first provide one basic tile which 20 | // tells the user what to do ("insert your smartcard"). Once the 21 | // user performs the action, then you can callback into LogonUI to 22 | // tell it that you have new tiles, and include a tile that is specific 23 | // to the user that the user can then interact with if necessary. 24 | 25 | #include 26 | #include "CSampleProvider.h" 27 | #include "CSampleCredential.h" 28 | #include "guid.h" 29 | #include 30 | 31 | // CSampleProvider //////////////////////////////////////////////////////// 32 | 33 | CSampleProvider::CSampleProvider(): 34 | _cRef(1), 35 | _pkiulSetSerialization(NULL), 36 | _dwCredUIFlags(0), 37 | _bRecreateEnumeratedCredentials(true), 38 | _bAutoSubmitSetSerializationCred(false), 39 | _bDefaultToFirstCredential(false) 40 | { 41 | DllAddRef(); 42 | 43 | ZeroMemory(_rgpCredentials, sizeof(_rgpCredentials)); 44 | } 45 | 46 | CSampleProvider::~CSampleProvider() 47 | { 48 | _ReleaseEnumeratedCredentials(); 49 | DllRelease(); 50 | } 51 | 52 | void CSampleProvider::_ReleaseEnumeratedCredentials() 53 | { 54 | for (int i = 0; i < ARRAYSIZE(_rgpCredentials); i++) 55 | { 56 | if (_rgpCredentials[i] != NULL) 57 | { 58 | _rgpCredentials[i]->Release(); 59 | } 60 | } 61 | } 62 | 63 | 64 | // SetUsageScenario is the provider's cue that it's going to be asked for tiles 65 | // in a subsequent call. 66 | // 67 | // This sample only handles the logon, unlock, and credui scenarios. 68 | HRESULT CSampleProvider::SetUsageScenario( 69 | CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus, 70 | DWORD dwFlags 71 | ) 72 | { 73 | HRESULT hr; 74 | 75 | _cpus = cpus; 76 | if (cpus == CPUS_CREDUI) 77 | { 78 | _dwCredUIFlags = dwFlags; // currently the only flags ever passed in are only valid for the credui scenario 79 | } 80 | _bRecreateEnumeratedCredentials = true; 81 | 82 | // unlike SampleCredentialProvider, we're not going to enumerate here. Instead, we'll store off the info 83 | // and then we'll wait for GetCredentialCount to enumerate. That way we'll know at enumeration time 84 | // whether we have a SetSerialization cred to deal with. That's a bit more important in the credUI case 85 | // than the logon case (although even in the logon case you could choose to only enumerate the SetSerialization 86 | // credential if there is one -- that's what the built-in password provider does). 87 | switch (cpus) 88 | { 89 | case CPUS_LOGON: 90 | case CPUS_UNLOCK_WORKSTATION: 91 | case CPUS_CREDUI: 92 | hr = S_OK; 93 | break; 94 | 95 | case CPUS_CHANGE_PASSWORD: 96 | hr = E_NOTIMPL; 97 | break; 98 | 99 | default: 100 | hr = E_INVALIDARG; 101 | break; 102 | } 103 | 104 | return hr; 105 | } 106 | 107 | // SetSerialization takes the kind of buffer that you would normally return to LogonUI for 108 | // an authentication attempt. It's the opposite of ICredentialProviderCredential::GetSerialization. 109 | // GetSerialization is implemented by a credential and serializes that credential. Instead, 110 | // SetSerialization takes the serialization and uses it to create a tile. 111 | // 112 | // SetSerialization is called for two main scenarios. The first scenario is in the credui case, which 113 | // we'll talk about in greater detail in a bit. The second situation is in a remote logon case 114 | // where the remote client may wish to prepopulate a tile with a username, or in some cases, 115 | // completely populate the tile and use it to logon without showing any UI. In this scenario, 116 | // typically the remote logon software would also come with a filter that would direct the 117 | // remote logon to the correct credential provider. 118 | // 119 | // This sample shows some advanced uses of SetSerialization in the CPUS_CREDUI scenario. 120 | // - if the in-cred's auth package is different than the auth package that we support, we 121 | // don't want to enumerate any tiles (since we can't provide creds that match the auth 122 | // package the caller is requesting). So we return a special return code from SetSerialization 123 | // that tells it we don't want it to call GetCredentialCount on us. 124 | // - Even if we can handle the auth package, both smartcards and username/password use our same 125 | // auth package. So we need to look at the MessageType to know if smartcard creds are 126 | // being requested. If they are, then we can't serialize a tile from this info. 127 | // - as long as CREDUIWIN_IN_CRED_ONLY is NOT specified, we enumerate our normal tiles, plus 128 | // an extra with the info from the in-cred specified (as long as we can handle the auth 129 | // package). 130 | // - if CREDUIWIN_IN_CRED_ONLY is specified (and we can handle the auth package and message type), 131 | // then only enumerate a tile with the info from the in-cred filled into it and no other tiles. 132 | // There are a few other credui scenarios that are not shown in this sample. Depending on your 133 | // purpose in writing a credprov that handles CPUS_CREDUI, you may or may not wish to handle those 134 | // scenarios. We suggest you read the technical references about the CREDUIWIN_* flags 135 | // for additional information. 136 | // 137 | STDMETHODIMP CSampleProvider::SetSerialization( 138 | const CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcs 139 | ) 140 | { 141 | HRESULT hr = E_INVALIDARG; 142 | 143 | if ((CLSID_CSampleProvider == pcpcs->clsidCredentialProvider) || (CPUS_CREDUI == _cpus)) 144 | { 145 | // Get the current AuthenticationPackageID that we are supporting 146 | ULONG ulNegotiateAuthPackage; 147 | hr = RetrieveNegotiateAuthPackage(&ulNegotiateAuthPackage); 148 | 149 | if (SUCCEEDED(hr)) 150 | { 151 | if (CPUS_CREDUI == _cpus) 152 | { 153 | if (CREDUIWIN_IN_CRED_ONLY & _dwCredUIFlags) 154 | { 155 | // If we are being told to enumerate only the incoming credential, we must not return 156 | // success unless we can enumerate it. We'll set hr to failure here and let it be 157 | // overridden if the enumeration logic below succeeds. 158 | hr = E_INVALIDARG; 159 | } 160 | else if (_dwCredUIFlags & CREDUIWIN_AUTHPACKAGE_ONLY) 161 | { 162 | if (ulNegotiateAuthPackage == pcpcs->ulAuthenticationPackage) 163 | { 164 | // In the credui case, SetSerialization should only ever return S_OK if it is able to serialize the input cred. 165 | // Unfortunately, SetSerialization had to be overloaded to indicate whether or not it will be able to GetSerialization 166 | // for the specific Auth Package that is being requested for CREDUIWIN_AUTHPACKAGE_ONLY to work, so when that flag is 167 | // set, it should return S_FALSE unless it is ALSO able to serialize the input cred, then it can return S_OK. 168 | // So in this case, we can set it to be S_FALSE because we support the authpackage, and then if we 169 | // can serialize the input cred, it will get overwritten with S_OK. 170 | hr = S_FALSE; 171 | } 172 | else 173 | { 174 | //we don't support this auth package, so we want to let logonUI know that by failing 175 | hr = E_INVALIDARG; 176 | } 177 | } 178 | } 179 | 180 | if ((ulNegotiateAuthPackage == pcpcs->ulAuthenticationPackage) && 181 | (0 < pcpcs->cbSerialization && pcpcs->rgbSerialization)) 182 | { 183 | KERB_INTERACTIVE_UNLOCK_LOGON* pkil = (KERB_INTERACTIVE_UNLOCK_LOGON*) pcpcs->rgbSerialization; 184 | if (KerbInteractiveLogon == pkil->Logon.MessageType) 185 | { 186 | // If there isn't a username, we can't serialize or create a tile for this credential. 187 | if (0 < pkil->Logon.UserName.Length && pkil->Logon.UserName.Buffer) 188 | { 189 | if ((CPUS_CREDUI == _cpus) && (CREDUIWIN_PACK_32_WOW & _dwCredUIFlags)) 190 | { 191 | BYTE* rgbNativeSerialization; 192 | DWORD cbNativeSerialization; 193 | if (SUCCEEDED(KerbInteractiveUnlockLogonRepackNative(pcpcs->rgbSerialization, pcpcs->cbSerialization, &rgbNativeSerialization, &cbNativeSerialization))) 194 | { 195 | KerbInteractiveUnlockLogonUnpackInPlace((PKERB_INTERACTIVE_UNLOCK_LOGON)rgbNativeSerialization, cbNativeSerialization); 196 | 197 | _pkiulSetSerialization = (PKERB_INTERACTIVE_UNLOCK_LOGON)rgbNativeSerialization; 198 | hr = S_OK; 199 | } 200 | } 201 | else 202 | { 203 | BYTE* rgbSerialization; 204 | rgbSerialization = (BYTE*)HeapAlloc(GetProcessHeap(), 0, pcpcs->cbSerialization); 205 | HRESULT hrCreateCred = rgbSerialization ? S_OK : E_OUTOFMEMORY; 206 | 207 | if (SUCCEEDED(hrCreateCred)) 208 | { 209 | CopyMemory(rgbSerialization, pcpcs->rgbSerialization, pcpcs->cbSerialization); 210 | KerbInteractiveUnlockLogonUnpackInPlace((KERB_INTERACTIVE_UNLOCK_LOGON*)rgbSerialization,pcpcs->cbSerialization); 211 | 212 | if (_pkiulSetSerialization) 213 | { 214 | HeapFree(GetProcessHeap(), 0, _pkiulSetSerialization); 215 | } 216 | _pkiulSetSerialization = (KERB_INTERACTIVE_UNLOCK_LOGON*)rgbSerialization; 217 | if (SUCCEEDED(hrCreateCred)) 218 | { 219 | // we allow success to override the S_FALSE for the CREDUIWIN_AUTHPACKAGE_ONLY, but 220 | // failure to create the cred shouldn't override that we can still handle 221 | // the auth package 222 | hr = hrCreateCred; 223 | } 224 | } 225 | } 226 | } 227 | } 228 | } 229 | } 230 | } 231 | 232 | return hr; 233 | } 234 | 235 | // Called by LogonUI to give you a callback. Providers often use the callback if they 236 | // some event would cause them to need to change the set of tiles that they enumerated 237 | HRESULT CSampleProvider::Advise( 238 | ICredentialProviderEvents* pcpe, 239 | UINT_PTR upAdviseContext 240 | ) 241 | { 242 | UNREFERENCED_PARAMETER(pcpe); 243 | UNREFERENCED_PARAMETER(upAdviseContext); 244 | 245 | return E_NOTIMPL; 246 | } 247 | 248 | // Called by LogonUI when the ICredentialProviderEvents callback is no longer valid. 249 | HRESULT CSampleProvider::UnAdvise() 250 | { 251 | return E_NOTIMPL; 252 | } 253 | 254 | // Called by LogonUI to determine the number of fields in your tiles. This 255 | // does mean that all your tiles must have the same number of fields. 256 | // This number must include both visible and invisible fields. If you want a tile 257 | // to have different fields from the other tiles you enumerate for a given usage 258 | // scenario you must include them all in this count and then hide/show them as desired 259 | // using the field descriptors. 260 | HRESULT CSampleProvider::GetFieldDescriptorCount( 261 | DWORD* pdwCount 262 | ) 263 | { 264 | *pdwCount = SFI_NUM_FIELDS; 265 | 266 | return S_OK; 267 | } 268 | 269 | // Gets the field descriptor for a particular field 270 | HRESULT CSampleProvider::GetFieldDescriptorAt( 271 | DWORD dwIndex, 272 | CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR** ppcpfd 273 | ) 274 | { 275 | HRESULT hr; 276 | 277 | // Verify dwIndex is a valid field. 278 | if ((dwIndex < SFI_NUM_FIELDS) && ppcpfd) 279 | { 280 | hr = FieldDescriptorCoAllocCopy(s_rgCredProvFieldDescriptors[dwIndex], ppcpfd); 281 | } 282 | else 283 | { 284 | hr = E_INVALIDARG; 285 | } 286 | 287 | return hr; 288 | } 289 | 290 | // Sets pdwCount to the number of tiles that we wish to show at this time. 291 | // Sets pdwDefault to the index of the tile which should be used as the default. 292 | // The default tile is the tile which will be shown in the zoomed view by default. If 293 | // more than one provider specifies a default tile the behavior is the last cred prov 294 | // get to specify the default tile. 295 | // If *pbAutoLogonWithDefault is TRUE, LogonUI will immediately call GetSerialization 296 | // on the credential you've specified as the default and will submit that credential 297 | // for authentication without showing any further UI. 298 | HRESULT CSampleProvider::GetCredentialCount( 299 | DWORD* pdwCount, 300 | DWORD* pdwDefault, 301 | BOOL* pbAutoLogonWithDefault 302 | ) 303 | { 304 | HRESULT hr = E_FAIL; 305 | if (_bRecreateEnumeratedCredentials) 306 | { 307 | _ReleaseEnumeratedCredentials(); 308 | hr = _CreateEnumeratedCredentials(); 309 | _bRecreateEnumeratedCredentials = false; 310 | } 311 | 312 | *pdwCount = 0; 313 | *pdwDefault = (_bDefaultToFirstCredential && _rgpCredentials[0]) ? 0 : CREDENTIAL_PROVIDER_NO_DEFAULT; 314 | *pbAutoLogonWithDefault = FALSE; 315 | 316 | if (SUCCEEDED(hr)) 317 | { 318 | // TODO: it would probably be nicer to keep a count of the number of creds 319 | DWORD dwNumCreds = 0; 320 | for (int i = 0; i < MAX_CREDENTIALS; i++) 321 | { 322 | if (_rgpCredentials[i] != NULL) 323 | { 324 | dwNumCreds++; 325 | } 326 | } 327 | 328 | switch(_cpus) 329 | { 330 | case CPUS_LOGON: 331 | if (_bAutoSubmitSetSerializationCred) 332 | { 333 | *pdwCount = 1; 334 | *pbAutoLogonWithDefault = TRUE; 335 | } 336 | else 337 | { 338 | 339 | *pdwCount = dwNumCreds; 340 | // since we have more than one tile and don't keep track of who logged on last, we don't really have a default in this case 341 | } 342 | hr = S_OK; 343 | break; 344 | 345 | case CPUS_UNLOCK_WORKSTATION: 346 | // in the unlock case, you likely would want to only enumerate tiles for the logged on user (that could be used to unlock) 347 | // but that's a bit complicated for a sample, so we'll just use our normal tiles 348 | // that we already set up in the logon case. The default out params set up at the top work for this case. 349 | *pdwCount = dwNumCreds; 350 | hr = S_OK; 351 | break; 352 | 353 | case CPUS_CREDUI: 354 | { 355 | *pdwCount = dwNumCreds; 356 | hr = S_OK; 357 | } 358 | break; 359 | 360 | default: 361 | hr = E_INVALIDARG; 362 | break; 363 | } 364 | } 365 | 366 | return hr; 367 | } 368 | 369 | // Returns the credential at the index specified by dwIndex. This function is called by logonUI to enumerate 370 | // the tiles. 371 | HRESULT CSampleProvider::GetCredentialAt( 372 | DWORD dwIndex, 373 | ICredentialProviderCredential** ppcpc 374 | ) 375 | { 376 | HRESULT hr; 377 | 378 | // Validate parameters. 379 | if((dwIndex < ARRAYSIZE(_rgpCredentials)) && _rgpCredentials[dwIndex] != NULL && ppcpc) 380 | { 381 | hr = _rgpCredentials[dwIndex]->QueryInterface(IID_ICredentialProviderCredential, reinterpret_cast(ppcpc)); 382 | } 383 | else 384 | { 385 | hr = E_INVALIDARG; 386 | } 387 | 388 | return hr; 389 | } 390 | 391 | // Creates a Credential with the SFI_USERNAME field's value set to pwzUsername. 392 | HRESULT CSampleProvider::_EnumerateOneCredential( 393 | DWORD dwCredentialIndex, 394 | PCWSTR pwzUsername 395 | ) 396 | { 397 | HRESULT hr; 398 | 399 | // Allocate memory for the new credential. 400 | CSampleCredential* ppc = new CSampleCredential(); 401 | 402 | if (ppc) 403 | { 404 | // Set the Field State Pair and Field Descriptors for ppc's fields 405 | // to the defaults (s_rgCredProvFieldDescriptors, and s_rgFieldStatePairs) and the value of SFI_USERNAME 406 | // to pwzUsername. 407 | hr = ppc->Initialize(_cpus,s_rgCredProvFieldDescriptors, s_rgFieldStatePairs, _dwCredUIFlags, pwzUsername); 408 | 409 | if (SUCCEEDED(hr)) 410 | { 411 | _rgpCredentials[dwCredentialIndex] = ppc; 412 | } 413 | else 414 | { 415 | // Release the pointer to account for the local reference. 416 | ppc->Release(); 417 | } 418 | } 419 | else 420 | { 421 | hr = E_OUTOFMEMORY; 422 | } 423 | 424 | return hr; 425 | } 426 | 427 | // 428 | // Depending on whether SetSerialization has been called and what CPUS we're in 429 | // creates the right set of credentials 430 | // 431 | HRESULT CSampleProvider::_CreateEnumeratedCredentials() 432 | { 433 | HRESULT hr = E_INVALIDARG; 434 | switch(_cpus) 435 | { 436 | case CPUS_LOGON: 437 | if (_pkiulSetSerialization) 438 | { 439 | hr = _EnumerateSetSerialization(); 440 | } 441 | else 442 | { 443 | hr = _EnumerateCredentials(); 444 | } 445 | break; 446 | 447 | case CPUS_CHANGE_PASSWORD: 448 | break; 449 | 450 | case CPUS_UNLOCK_WORKSTATION: 451 | // a more advanced implementation would only enumerate tiles that could gather creds for the logged on user 452 | // since those are the only creds that will work to unlock the session 453 | // but we're going with this for simplicity 454 | hr = _EnumerateCredentials(); 455 | break; 456 | 457 | case CPUS_CREDUI: 458 | _bDefaultToFirstCredential = true; 459 | 460 | if (_pkiulSetSerialization) 461 | { 462 | hr = _EnumerateSetSerialization(); 463 | } 464 | if (_dwCredUIFlags & CREDUIWIN_ENUMERATE_ADMINS) 465 | { 466 | // this sample doesn't handle this particular case 467 | // You would want to handle this in order to participate 468 | // User Account Control elevations for a non-admin users (where all the 469 | // admins tiles are enumerated) 470 | } 471 | else if (!(_dwCredUIFlags & CREDUIWIN_IN_CRED_ONLY)) 472 | { 473 | // if we're here, then we're supposed to enumerate whatever we should enumerate for the normal case. 474 | // In our case, that's our 2 tiles. We may already have one tile, though 475 | if (_pkiulSetSerialization && SUCCEEDED(hr)) 476 | { 477 | hr = _EnumerateCredentials(true); 478 | } 479 | else 480 | { 481 | hr = _EnumerateCredentials(false); 482 | } 483 | } 484 | break; 485 | 486 | default: 487 | break; 488 | } 489 | return hr; 490 | } 491 | 492 | 493 | // Sets up the normal 2 tiles for this provider (Administrator and Guest) 494 | HRESULT CSampleProvider::_EnumerateCredentials(bool bAlreadyHaveSetSerializationCred) 495 | { 496 | DWORD dwStart = bAlreadyHaveSetSerializationCred ? 1 : 0; 497 | HRESULT hr = _EnumerateOneCredential(dwStart++, L"Administrator"); 498 | 499 | return hr; 500 | } 501 | 502 | // This enumerates a tile for the info in _pkiulSetSerialization. See the SetSerialization function comment for 503 | // more information. 504 | HRESULT CSampleProvider::_EnumerateSetSerialization() 505 | { 506 | KERB_INTERACTIVE_LOGON* pkil = &_pkiulSetSerialization->Logon; 507 | 508 | _bAutoSubmitSetSerializationCred = false; 509 | _bDefaultToFirstCredential = false; 510 | 511 | // Since this provider only enumerates local users (not domain users) we are ignoring the domain passed in. 512 | // However, please note that if you receive a serialized cred of just a domain name, that domain name is meant 513 | // to be the default domain for the tiles (or for the empty tile if you have one). Also, depending on your scenario, 514 | // the presence of a domain other than what you're expecting might be a clue that you shouldn't handle 515 | // the SetSerialization. For example, in this sample, we could choose to not accept a serialization for a cred 516 | // that had something other than the local machine name as the domain. 517 | 518 | // Use a "long" (MAX_PATH is arbitrary) buffer because it's hard to predict what will be 519 | // in the incoming values. A DNS-format domain name, for instance, can be longer than DNLEN. 520 | WCHAR wszUsername[MAX_PATH] = {0}; 521 | WCHAR wszPassword[MAX_PATH] = {0}; 522 | 523 | // since this sample assumes local users, we'll ignore domain. If you wanted to handle the domain 524 | // case, you'd have to update CSampleCredential::Initialize to take a domain. 525 | HRESULT hr = StringCbCopyNW(wszUsername, sizeof(wszUsername), pkil->UserName.Buffer, pkil->UserName.Length); 526 | 527 | if (SUCCEEDED(hr)) 528 | { 529 | hr = StringCbCopyNW(wszPassword, sizeof(wszPassword), pkil->Password.Buffer, pkil->Password.Length); 530 | 531 | if (SUCCEEDED(hr)) 532 | { 533 | CSampleCredential* pCred = new CSampleCredential(); 534 | 535 | if (pCred) 536 | { 537 | hr = pCred->Initialize(_cpus, s_rgCredProvFieldDescriptors, s_rgFieldStatePairs, _dwCredUIFlags, wszUsername, wszPassword); 538 | 539 | if (SUCCEEDED(hr)) 540 | { 541 | // for the purposes of this sample, when we enumerate the SetSerialization cred, we only enumerate 542 | // that cred and no others, so we can assume it just goes in slot 0. 543 | _rgpCredentials[0] = pCred; 544 | 545 | //if we were able to create a cred, default to it 546 | _bDefaultToFirstCredential = true; 547 | } 548 | } 549 | else 550 | { 551 | hr = E_OUTOFMEMORY; 552 | } 553 | 554 | // If we were passed all the info we need (in this case username & password), we're going to automatically submit this credential. 555 | // (if we're in CPUS_LOGON that is. In credUI we want the user to at least click the tile to choose to use those creds) 556 | if (SUCCEEDED(hr) && (0 < wcslen(wszPassword))) 557 | { 558 | _bAutoSubmitSetSerializationCred = true; 559 | } 560 | } 561 | } 562 | 563 | 564 | return hr; 565 | } 566 | 567 | // Boilerplate code to create our provider. 568 | HRESULT CSampleProvider_CreateInstance(REFIID riid, void** ppv) 569 | { 570 | HRESULT hr; 571 | 572 | CSampleProvider* pProvider = new CSampleProvider(); 573 | 574 | if (pProvider) 575 | { 576 | hr = pProvider->QueryInterface(riid, ppv); 577 | pProvider->Release(); 578 | } 579 | else 580 | { 581 | hr = E_OUTOFMEMORY; 582 | } 583 | 584 | return hr; 585 | } 586 | --------------------------------------------------------------------------------