Skip to content

Commit

Permalink
multiOTP Credential Provider 5.1.0.7
Browse files Browse the repository at this point in the history
FIX: [Receive an OTP by SMS] link is now fixed for Windows 10
ENH: Credential Provider registry entries are now always used when calling multiOTP.exe
  • Loading branch information
multiOTP committed Feb 27, 2018
1 parent 9f6fcd0 commit 909a56a
Show file tree
Hide file tree
Showing 18 changed files with 391 additions and 269 deletions.
44 changes: 10 additions & 34 deletions @multiOTPCredentialProvider.iss
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!

#define MyAppName "multiOTP Credential Provider"
#define MyAppVersion "5.1.0.5"
#define MyAppVersion "5.1.0.7"
#define MyAppShortName "multiOTP"
#define MyAppPublisher "SysCo systemes de communication sa"
#define MyAppURL "https://github.com/multiOTP/multiOTPCredentialProvider"
Expand All @@ -28,10 +28,10 @@ DefaultGroupName={#MyAppName}
UninstallDisplayIcon={app}\multiotp.exe
DisableProgramGroupPage=yes
OutputDir=D:\Data\projects\multiotp\multiOTPCredentialProvider\installer
OutputBaseFilename=multiOTPCredentialProvider-5.1.0.5
OutputBaseFilename=multiOTPCredentialProvider-5.1.0.7
SetupIconFile=D:\Data\projects\multiotp\ico\multiOTP.ico
WizardImageFile=D:\Data\projects\multiotp\bmp\multiOTP-wizard-164x314.bmp
WizardSmallImageFile=D:\Data\projects\multiotp\bmp\multiOTP-wizard-55x58.bmp
WizardImageFile=..\bmp\multiOTP-wizard-164x314.bmp
WizardSmallImageFile=..\bmp\multiOTP-wizard-55x58.bmp
Compression=lzma
SolidCompression=yes
; "ArchitecturesInstallIn64BitMode=x64" requests that the install be
Expand All @@ -57,6 +57,9 @@ Source: "stable\multiotp.exe"; DestDir: "{app}"; Flags: ignoreversion; AfterInst
Source: "stable\x64\multiOTPCredentialProvider.dll"; DestDir: "{sys}"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "stable\i386\multiOTPCredentialProvider.dll"; DestDir: "{sys}"; Flags: ignoreversion; Check: not Is64BitInstallMode
Source: "stable\php\*"; DestDir: "{app}\php"; Flags: ignoreversion createallsubdirs recursesubdirs
Source: "..\core\qrcode\*"; DestDir: "{app}\qrcode"; Flags: ignoreversion createallsubdirs recursesubdirs
Source: "..\core\templates\emailtemplate.html"; DestDir: "{app}\templates"; Flags: ignoreversion
Source: "..\core\templates\scratchtemplate.html"; DestDir: "{app}\templates"; Flags: ignoreversion

[Icons]
Name: "{group}\{cm:ProgramOnTheWeb,{#MyAppName}}"; Filename: "{#MyAppURL}"
Expand Down Expand Up @@ -416,7 +419,6 @@ begin
Width := Page.SurfaceWidth - Left;
Text := multiOTPServers;
end;
// pageTop := pageTop + multiOTPServersEdit.Height + ScaleY(3);
pageTop := pageTop + 2 * multiOTPServersEdit.Height;
multiOTPServerTimeoutLabel := TNewStaticText.Create(Page);
Expand Down Expand Up @@ -452,17 +454,14 @@ begin
Caption := ExpandConstant('{cm:multiOTPSharedSecretLabel}');
Parent := Page.Surface;
end;
// pageTop := pageTop + multiOTPSharedSecretLabel.Height + ScaleY(0);
pageTop := pageTop + multiOTPSharedSecretLabel.Height + ScaleY(0);
multiOTPSharedSecretEdit := TEdit.Create(Page);
with multiOTPSharedSecretEdit do
begin
Parent := Page.Surface;
// Left := pageLeft + 6 + multiOTPSharedSecretLabel.Width;
Left := pageLeft;
// Top := pageTop - ScaleY(3);
Top := pageTop;
Width := 20 * ScaleX(multiOTPSharedSecretLabel.Font.Size);
Text := multiOTPSharedSecret;
Expand Down Expand Up @@ -607,22 +606,6 @@ begin
end;
pageTop := pageTop + multiOTPTimeoutLabel.Height + ScaleY(0);
// Add items (False means it's not a password edit)
//WizardPage.Add('URL of your multiOTP server(s), separated with a ; if more than one : ', False);
//WizardPage.Add('Timeout before switching to the next server : ', False);
//WizardPage.Add('Secret shared with your server(s) (Configuration / Devices / Secret) : ', False);
// Set initial values (optional)
//WizardPage.Values[0] := ExpandConstant('https://192.168.1.88');
//WizardPage.Values[1] := ExpandConstant('5');
//WizardPage.Values[2] := ExpandConstant('MySharedSecret');
// Read values into variables
//multiOTPServers := WizardPage.Values[0];
//multiOTPServerTimeout := WizardPage.Values[1];
//multiOTPSecret := WizardPage.Values[1];
end;
Expand Down Expand Up @@ -699,9 +682,6 @@ begin
ResultCode := 99;
end;
// multiOTPOptions := 'server_secret='+multiOTPSharedSecret+Chr(9)+'server_cache_level='+IntToStr(multiOTPCacheEnabled)+Chr(9)+'server_timeout='+IntToStr(multiOTPServerTimeout)+Chr(9)+'server_url='+multiOTPServers+''
// RegWriteStringValue(HKEY_CLASSES_ROOT, 'CLSID\{FCEFDFAB-B0A1-4C4D-8B2B-4FF4E0A3D978}','multiOTPOptions', multiOTPOptions);
// Get multiOTP version
TmpFileName := ExpandConstant('{tmp}\multiotp_version.txt');
Exec('>', 'cmd.exe /C multiotp.exe -cp -version > "' + TmpFileName + '"', ExpandConstant('{app}'), SW_HIDE, ewWaitUntilTerminated, ResultCode);
Expand Down Expand Up @@ -811,7 +791,6 @@ begin
Caption := ExpandConstant('{cm:multiOTPWindowsUsername} : ');
Parent := testPage.Surface;
end;
// pageTop := pageTop + testUsernameLabel.Height + ScaleY(0);
testUsernameEdit := TEdit.Create(testPage);
with testUsernameEdit do
Expand All @@ -834,7 +813,6 @@ begin
Caption := ExpandConstant('{cm:multiOTPWindowsPassword} : ');
Parent := testPage.Surface;
end;
// pageTop := pageTop + testPasswordLabel.Height + ScaleY(2);
testPasswordEdit := TEdit.Create(testPage);
with testPasswordEdit do
Expand All @@ -858,7 +836,6 @@ begin
Caption := ExpandConstant('{cm:multiOTPUserOTP} : ');
Parent := testPage.Surface;
end;
// pageTop := pageTop + testOtpLabel.Height + ScaleY(2);
testOtpdEdit := TEdit.Create(testPage);
with testOtpdEdit do
Expand Down Expand Up @@ -892,7 +869,6 @@ begin
Caption := ExpandConstant('{cm:multiOTPTestResult} : ');
Parent := testPage.Surface;
end;
// pageTop := pageTop + testPasswordLabel.Height + ScaleY(2);
testButtonResult := TNewStaticText.Create(testPage);
with testButtonResult do
Expand Down Expand Up @@ -990,9 +966,9 @@ begin
credentialProviderInstalled := false;
// Create two custom pages
CreateSetupPage2of2;
CreateSetupPage1of2;
CreateTestPage;
CreateSetupPage2of2; // Create first the second page (after wpSelectTasks)
CreateSetupPage1of2; // Create the first page (which is now just after wpSelectTasks)
CreateTestPage; // This page is after wpInstalling
// Test variables initialization
testDone := false;
Expand Down
153 changes: 116 additions & 37 deletions CSampleCredential.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ HRESULT CSampleCredential::call_multiotp(_In_ PCWSTR username, _In_ PCWSTR PREV_
STARTUPINFO si;
PROCESS_INFORMATION pi;
DWORD exitCode;
wchar_t cmd[1024];
wchar_t cmd[2048];
wchar_t options[2048];
size_t len;
PWSTR path;

Expand All @@ -105,26 +106,26 @@ HRESULT CSampleCredential::call_multiotp(_In_ PCWSTR username, _In_ PCWSTR PREV_

//cmd = (PWSTR)CoTaskMemAlloc(sizeof(wchar_t) * (len + 1));//+1 null pointer

wcscpy_s(cmd, 1024, L"-cp ");
wcscpy_s(cmd, 2048, L"-cp ");

if (DEVELOP_MODE) {
wcscat_s(cmd, 1024, L"-debug ");
wcscat_s(cmd, 2048, L"-debug ");
}

if (wcslen(PREV_OTP) > 0) {
wcscat_s(cmd, 1024, L"-resync ");
wcscat_s(cmd, 2048, L"-resync ");
}

wcscat_s(cmd, 1024, username);
wcscat_s(cmd, 1024, L" ");
wcscat_s(cmd, 2048, username);
wcscat_s(cmd, 2048, L" ");

wcscat_s(cmd, 1024, PREFIX_PASS);
wcscat_s(cmd, 2048, PREFIX_PASS);

if (wcslen(PREV_OTP) > 0) {
wcscat_s(cmd, 1024, PREV_OTP);
wcscat_s(cmd, 1024, L" ");
wcscat_s(cmd, 2048, PREV_OTP);
wcscat_s(cmd, 2048, L" ");
}
wcscat_s(cmd, 1024, OTP);
wcscat_s(cmd, 2048, OTP);

len = wcslen(cmd);
if (DEVELOP_MODE) PrintLn("command len:%d", int(len));
Expand All @@ -141,18 +142,58 @@ HRESULT CSampleCredential::call_multiotp(_In_ PCWSTR username, _In_ PCWSTR PREV_

timeout = readRegistryValueInteger(CONF_TIMEOUT, timeout);

wchar_t appname[1024];
DWORD server_timeout = 5;
DWORD server_cache_level = 1;
PWSTR shared_secret;
PWSTR servers;

server_timeout = readRegistryValueInteger(CONF_SERVER_TIMEOUT, server_timeout);
wchar_t server_timeout_string[1024];
_ultow_s(server_timeout, server_timeout_string, 10);
wcscpy_s(options, 2048, L"-server-timeout=");
wcscat_s(options, 2048, server_timeout_string);
wcscat_s(options, 2048, L" ");

server_cache_level = readRegistryValueInteger(CONF_CACHE_ENABLED, server_cache_level);
wchar_t server_cache_level_string[1024];
_ultow_s(server_cache_level, server_cache_level_string, 10);
wcscat_s(options, 2048, L"-server-cache-level=");
wcscat_s(options, 2048, server_cache_level_string);
wcscat_s(options, 2048, L" ");

if (readRegistryValueString(CONF_SERVERS, &servers, L"")) {
wcscat_s(options, 2048, L"-server-url=");
wcscat_s(options, 2048, servers);
wcscat_s(options, 2048, L" ");
}

if (readRegistryValueString(CONF_SHARED_SECRET, &shared_secret, L"ClientServerSecret")) {
wcscat_s(options, 2048, L"-server-secret=");
wcscat_s(options, 2048, shared_secret);
wcscat_s(options, 2048, L" ");
}

wcscat_s(options, 2048, cmd);

wchar_t appname[2048];

wcscpy_s(appname, 1024, path);
wcscpy_s(appname, 2048, L"\"");
wcscat_s(appname, 2048, path);
size_t npath = wcslen(appname);
if (appname[npath - 1] != '\\' && appname[npath - 1] != '/') {
appname[npath] = '\\';
appname[npath+1] = '\0';
}
wcscat_s(appname, 1024, L"multiotp.exe");
wcscat_s(appname, 2048, L"multiotp.exe");
wcscat_s(appname, 2048, L"\"");
wcscat_s(appname, 2048, L" ");
wcscat_s(appname, 2048, options);

if (DEVELOP_MODE) PrintLn(L"Calling ", appname);
if (::CreateProcessW(appname, cmd, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, path, &si, &pi)) {
if (DEVELOP_MODE) PrintLn(L"with options ", options);
// if (::CreateProcessW(appname, options, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, path, &si, &pi)) {
// As argc 0 is the full filename itself, we use the lpCommandLine only
if (::CreateProcessW(NULL, appname, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, path, &si, &pi)) {

DWORD result = WaitForSingleObject(pi.hProcess, (timeout * 1000));

Expand Down Expand Up @@ -1003,11 +1044,12 @@ HRESULT CSampleCredential::CommandLinkClicked(DWORD dwFieldID)

PWSTR pszDomain;
PWSTR pszUsername;
PWSTR pszQualifiedUserName;
PWSTR pszNetBiosDomainName = L"";

ULONG size = 1024;
wchar_t buffer[1024];

wchar_t fullname[1024];
wchar_t uname[1024];
wchar_t upn_name[1024];
wchar_t otp_name[1024];
Expand All @@ -1018,34 +1060,72 @@ HRESULT CSampleCredential::CommandLinkClicked(DWORD dwFieldID)
BOOLEAN rc;

hr_sfi = SHStrDupW(L"", &pszUsername);
hr_sfi = SHStrDupW(_rgFieldStrings[SFI_LOGIN_NAME], &pszQualifiedUserName);

const wchar_t *pchWhack = wcschr(pszQualifiedUserName, L'\\');
const wchar_t *pchWatSign = wcschr(pszQualifiedUserName, L'@');
dwDomainSize = readRegistryValueString(CONF_DOMAIN_NAME, &pszDomain, L"");
if (DEVELOP_MODE) PrintLn(L"Detected domain: ", pszDomain);
if (DEVELOP_MODE) PrintLn(L"Detected domain size: %d", dwDomainSize);

if (_fUserNameVisible) {
//username is entered by the user
CoTaskMemFree(_pszQualifiedUserName);
hr_sfi = SHStrDupW(_rgFieldStrings[SFI_LOGIN_NAME], &_pszQualifiedUserName);
}

if (DEVELOP_MODE) PrintLn(L"_pszQualifiedUserName: ", _pszQualifiedUserName);

if (DEVELOP_MODE) PrintLn(L"OTP Username determination");
const wchar_t *pchWhack = wcschr(_pszQualifiedUserName, L'\\');
const wchar_t *pchWatSign = wcschr(_pszQualifiedUserName, L'@');

DOMAIN_CONTROLLER_INFO* pDCI;
if (DsGetDcNameW(NULL, pszDomain, NULL, NULL, DS_IS_DNS_NAME | DS_RETURN_FLAT_NAME, &pDCI) == ERROR_SUCCESS) {
pszNetBiosDomainName = pDCI->DomainName;
// NetApiBufferFree(pDCI);
}

if ((dwDomainSize > 0) && (pchWatSign == nullptr) && (pchWhack == nullptr)) {
if (DEVELOP_MODE) PrintLn(L"Take the default domain ", pszDomain, L" - ", pszNetBiosDomainName);
wcscpy_s(fullname, 1024, pszNetBiosDomainName);
wcscat_s(fullname, 1024, L"\\");
wcscat_s(fullname, 1024, _pszQualifiedUserName);
CoTaskMemFree(_pszQualifiedUserName);
hr = SHStrDupW(fullname, &_pszQualifiedUserName);
pchWhack = wcschr(fullname, L'\\');
if (DEVELOP_MODE) PrintLn(L"The full user has been defined like this: ", fullname);
}

if (pchWatSign != nullptr) {
wcscpy_s(upn_name, 1024, pszQualifiedUserName);
rc = TranslateNameW(pszQualifiedUserName, NameUserPrincipal, NameSamCompatible, buffer, &size);
wcscpy_s(upn_name, 1024, _pszQualifiedUserName);
rc = TranslateNameW(_pszQualifiedUserName, NameUserPrincipal, NameSamCompatible, buffer, &size);
if (rc) {
if (DEVELOP_MODE) PrintLn(L"User translated from ", pszQualifiedUserName, L" to ", buffer);
CoTaskMemFree(pszQualifiedUserName);
wcscpy_s(uname, 1024, buffer);
if (DEVELOP_MODE) PrintLn(L"User translated from ", _pszQualifiedUserName, L" to ", buffer);
CoTaskMemFree(_pszQualifiedUserName);
hr = SHStrDupW(buffer, &_pszQualifiedUserName);
pchWhack = wcschr(buffer, L'\\');
}
} else if (pchWhack != nullptr) {
hr_sfi = SplitDomainAndUsername(pszQualifiedUserName, &pszDomain, &pszUsername);
if (SUCCEEDED(hr_sfi)) {
wcscpy_s(uname, 1024, pszUsername);
rc = TranslateNameW(pszQualifiedUserName, NameSamCompatible, NameUserPrincipal, buffer, &size);
if (rc) {
if (DEVELOP_MODE) PrintLn(L"User translated from ", pszQualifiedUserName, L" to ", buffer);
CoTaskMemFree(pszQualifiedUserName);
wcscpy_s(upn_name, 1024, buffer);
}
} else {
rc = TranslateNameW(_pszQualifiedUserName, NameSamCompatible, NameUserPrincipal, buffer, &size);
if (rc) {
if (DEVELOP_MODE) PrintLn(L"User translated to UPN, from ", _pszQualifiedUserName, L" to ", buffer);
wcscpy_s(upn_name, 1024, buffer);
}
}

if (pchWhack != nullptr) {
const wchar_t *pchUsernameBegin = pchWhack + 1;
hr = wcscpy_s(uname, 1024, pchUsernameBegin);
} else {
wcscpy_s(upn_name, 1024, pszQualifiedUserName);
wcscpy_s(uname, 1024, pszQualifiedUserName);
CoTaskMemFree(pszQualifiedUserName);
hr = wcscpy_s(uname, 1024, _pszQualifiedUserName);
// 2017-11-05 SysCo/al Add UPN support
if (pchWatSign == nullptr) {
//append localhost as a domain for windows logon
wcscpy_s(fullname, 1024, L".\\");
wcscat_s(fullname, 1024, _pszQualifiedUserName);
CoTaskMemFree(_pszQualifiedUserName);
hr = SHStrDupW(fullname, &_pszQualifiedUserName);
}

if (DEVELOP_MODE) PrintLn(L"_pszQualifiedUserName with domain: ", _pszQualifiedUserName);
}

if (readRegistryValueInteger(CONF_UPN_FORMAT, 0)) {
Expand All @@ -1061,7 +1141,6 @@ HRESULT CSampleCredential::CommandLinkClicked(DWORD dwFieldID)
default:
hr = E_INVALIDARG;
}

}
else
{
Expand Down
7 changes: 5 additions & 2 deletions CSampleCredential.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,17 @@ class CSampleCredential : public ICredentialProviderCredential2, ICredentialProv

IFACEMETHODIMP QueryInterface(_In_ REFIID riid, _COM_Outptr_ void **ppv)
{
static const QITAB qit[] =
#pragma warning( push )
#pragma warning( disable : 4838)
static const QITAB qit[] =
{
QITABENT(CSampleCredential, ICredentialProviderCredential), // IID_ICredentialProviderCredential
QITABENT(CSampleCredential, ICredentialProviderCredential2), // IID_ICredentialProviderCredential2
QITABENT(CSampleCredential, ICredentialProviderCredentialWithFieldOptions), //IID_ICredentialProviderCredentialWithFieldOptions
{ static_cast<int>(0) },
};
return QISearch(this, qit, riid, ppv);
#pragma warning( pop )
return QISearch(this, qit, riid, ppv);
}
public:
// ICredentialProviderCredential
Expand Down
2 changes: 1 addition & 1 deletion CSampleProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@ void CSampleProvider::_CreateEnumeratedCredentials()
void CSampleProvider::_ReleaseEnumeratedCredentials()
{
if (DEVELOP_MODE) PrintLn("_ReleaseEnumeratedCredentials");
for (int i = 0; i < _pCredential.size(); i++) {
for (DWORD i = 0; i < _pCredential.size(); i++) {
if (_pCredential[i] != nullptr)
{
_pCredential[i]->Release();
Expand Down
Loading

0 comments on commit 909a56a

Please sign in to comment.