Related
I've written a credential provider and a key storage provider to logon to windows via certificate. As the documentation in this points is quite vague I used different samples from Microsoft to get things working.
I think I'm nearly there, but the logon behaves unpredictably. Sometimes I get through to the kerberos server (which complains about the certificate), sometimes the process fails with 0x80090029 without any information and sometimes windows crashes. As these crashes all have to do with access violations or null pointers and happen to occur in various places (kerberos.dll, Windows.UI.Logon.dll, ...) I think it has something to do with my key structure that i point the given NCRYT_KEY_HANDLE to in my OpenKey-implementation.
The KeyStorageProviderSample in the CNG-Kit has an example, but relies on a RSA-key stored in %AppData%. I don't have the private key available as it is stored in secure hardware, I just have the public part (i.e. the public certificate), that I read from another device and import via the following code:
SECURITY_STATUS WINAPI KeyHandler::ReadPemCert(__inout KSP_KEY *keyHandle)
{
LOG_FUNCTION;
CERT_CONTEXT certContext = {};
DWORD readLength = 0;
LOG("Fetch certificate");
const int maxSizeInBytes = 4096;
char pemCertificateAsBytes[maxSizeInBytes];
BluetoothClient bluetoothClient = BluetoothClient();
bluetoothClient.getCertificate((PBYTE)pemCertificateAsBytes, readLength);
DWORD certAsDerLen = readLength;
BYTE* certAsDer = new BYTE[certAsDerLen];
LOG("convert PEM to DER");
if (!CryptStringToBinaryA(pemCertificateAsBytes, 0, CRYPT_STRING_BASE64, certAsDer, &certAsDerLen, NULL, NULL))
{
LOG_LAST_ERROR("CryptStringToBinary failed. Err:");
}
LOG_BYTES_AS_HEX("DER-Zertifikat", certAsDer, certAsDerLen);
PCCERT_CONTEXT pcCertContext = CertCreateCertificateContext(X509_ASN_ENCODING, certAsDer, certAsDerLen);
certContext->pCertInfo = pcCertContext->pCertInfo;
certContext->cbCertEncoded = pcCertContext->cbCertEncoded;
certContext->pbCertEncoded = pcCertContext->pbCertEncoded;
certContext->dwCertEncodingType = pcCertContext->dwCertEncodingType;
CERT_INFO *certInfo;
certInfo = certContext.pCertInfo;
CERT_PUBLIC_KEY_INFO pubKeyInfo = certInfo->SubjectPublicKeyInfo;
LOG("Aquire cryptocontext");
HCRYPTPROV hProv = 0;
if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
{
{
LOG_LAST_ERROR("CryptAcquireContext failed. Err:");
return -1;
}
}
LOG("Importing public key");
NCRYPT_KEY_HANDLE publicKeyHandle = NULL;
if (!CryptImportPublicKeyInfo(hProv, X509_ASN_ENCODING, &pubKeyInfo, &publicKeyHandle))
{
LOG_LAST_ERROR("CryptImportPublicKeyInfo failed. Err:");
return -1;
}
keyHandle->fFinished = TRUE;
keyHandle->hPublicKey = (BCRYPT_KEY_HANDLE)publicKeyHandle;
keyHandle->pszKeyBlobType = BCRYPT_RSAPUBLIC_BLOB;
LocalFree(certInfo);
return ERROR_SUCCESS;
}
The key structure is initialized this way:
SECURITY_STATUS
WINAPI
KeyHandler::CreateNewKeyObject(
__in_opt LPCWSTR pszKeyName,
__deref_out KSP_KEY **ppKey)
{
LOG_FUNCTION;
KSP_KEY *pKey = NULL;
DWORD cbKeyName = 0;
SECURITY_STATUS Status = NTE_INTERNAL_ERROR;
NTSTATUS ntStatus = STATUS_INTERNAL_ERROR;
pKey = (KSP_KEY *)HeapAlloc(GetProcessHeap(), 0, sizeof(KSP_KEY));
if (pKey == NULL)
{
return NTE_NO_MEMORY;
}
pKey->cbLength = sizeof(KSP_KEY);
pKey->dwMagic = KSP_KEY_MAGIC;
pKey->dwAlgID = KSP_RSA_ALGID;
pKey->pszKeyFilePath = NULL;
pKey->pszKeyBlobType = NULL;
pKey->dwKeyBitLength = 0;
pKey->fFinished = FALSE;
//Copy the keyname into the key struct.
if (pszKeyName != NULL)
{
cbKeyName = (DWORD)(wcslen(pszKeyName) + 1) * sizeof(WCHAR);
pKey->pszKeyName = (LPWSTR)HeapAlloc(
GetProcessHeap(),
0,
cbKeyName + sizeof(WCHAR));
if (pKey->pszKeyName == NULL)
{
return NTE_NO_MEMORY;
}
CopyMemory(pKey->pszKeyName, pszKeyName, cbKeyName);
pKey->pszKeyName[cbKeyName / sizeof(WCHAR)] = L'\0';
}
else
{
pKey->pszKeyName = NULL;
}
if (globalRSAProviderHandle == NULL)
{
ntStatus = BCryptOpenAlgorithmProvider(
&globalRSAProviderHandle,
BCRYPT_RSA_ALGORITHM,
NULL,
0);
if (!NT_SUCCESS(ntStatus))
{
return NormalizeNteStatus(ntStatus);
}
}
pKey->hProvider = globalRSAProviderHandle;
pKey->pbKeyFile = NULL;
pKey->cbKeyFile = 0;
pKey->pbPrivateKey = NULL;
pKey->cbPrivateKey = 0;
pKey->hPublicKey = NULL;
pKey->hPrivateKey = NULL;
pKey->dwExportPolicy = NCRYPT_ALLOW_EXPORT_FLAG | NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG;
pKey->dwKeyUsagePolicy = NCRYPT_ALLOW_DECRYPT_FLAG | NCRYPT_ALLOW_SIGNING_FLAG;
pKey->pbSecurityDescr = NULL;
pKey->cbSecurityDescr = 0;
InitializeListHead(&pKey->PropertyList);
*ppKey = pKey;
pKey = NULL;
return ERROR_SUCCESS;
}
Somewhere in there must be the mistake leading to the various memory errors. But as I'm quite new to windows programming and c/c++ I just can't spot the point and can't find any documentation about the datastructure that windows expects for the NCRYTP_KEY_HANDLE.
Does anybody know more about this structure?
NCRYPT_KEY_HANDLE is just a pointer to a structure that you defined.
Windows itself doesn't care about this structure and expect that your provider knows how to work with it.
In KeyHandler::ReadPemCert you mixed legacy CryptoAPI and CNG API. Since you are implementing KSP you should use only CNG API (CryptImportPublicKeyInfoEx2).
DWORD error = NTE_FAIL;
BCRYPT_KEY_HANDLE hKey = NULL;
...
PCCERT_CONTEXT pcCertContext = CertCreateCertificateContext(X509_ASN_ENCODING, certAsDer, certAsDerLen);
if(!pcCertContext)
{
goto Exit;
}
if (!CryptImportPublicKeyInfoEx2(X509_ASN_ENCODING, &pcCertContext->pCertInfo->SubjectPublicKeyInfo, 0, nullptr, &hKey))
{
goto Exit;
}
/* Also you can export key and print out the result to make sure everything works
DWORD temp = 0;
status = BCryptExportKey(hKey, 0, BCRYPT_RSAPUBLIC_BLOB, nullptr, 0, &temp, 0);
if (status != ERROR_SUCCESS)
{
goto Exit;
}
std::vector<BYTE> key(temp);
status = BCryptExportKey(hKey, 0, BCRYPT_RSAPUBLIC_BLOB, key.data(), key.size(), &temp, 0);
if (status != ERROR_SUCCESS)
{
goto Exit;
}
for (auto const& i : key)
{
std::cout << std::hex << (int)i;
}
}
*/
keyHandle->fFinished = TRUE;
keyHandle->hPublicKey = hKey;
keyHandle->pszKeyBlobType = BCRYPT_RSAPUBLIC_BLOB;
erro = ERROR_SUCCESS;
Exit:
if(pcCertContext)
{
CertFreeCertificateContext(pcCertContext);
}
return error;
I started developing a Firefox add-on, however I could not find any IDE specifically for Firefox. For most part it doesn't really matter because I can just open Javascript files and edit them (I use VS2013 and Web Essentials (I think)).
Up to this point everything is acceptable, but when I have to use cmd every time to run this plugin and then read console logs from cmd, it becomes a nightmare.
So my is - is there some way to launch, develop and log Firefox plugin just like any code in Visual Studio 2013? Other IDEs are welcome too.
Well I think it would be possible to create Visual Studio add-on, but it just too much work. However, I managed to partly integrate Firefox add-on creation into VS2013 with c++ code. It redirects cmd window so that means, that you'll output from cmd in "Output" window while debugging.
I'm leaving complete code with steps in case someone else needs this (C++11 is required):
Create Win32 C++ project (not cmd one).
Paste code (below) into cpp file.
Change YOUR_EXTENSION_NAME to your add-on name.
Run code once, it should throw message box with info where to put Add-on SDK.
Copy SDK files to that folder.
Run code again and exit (you may exit however you want, it should terminate remaining windows).
Now there are 3 options for file (.js, .css, etc.) linking:
Create files manually in SDK folder and add them manually to project.
Create files via VS2013 menu and then uncomment and modify, add, delete lines in do while loop.
Create files via VS2013 menu, but choose SDK folders.
Code:
#include <windows.h>
#include <tchar.h>
#include <thread>
#include <chrono>
#include <typeinfo>
#include <Shlwapi.h>
#pragma comment(lib,"Shlwapi.lib")
// Timer code start
/*
//
//Credit goes to James Daughtry for this piece of code
//
*/
class Timer {
typedef std::chrono::high_resolution_clock high_resolution_clock;
typedef std::chrono::milliseconds milliseconds;
public:
Timer(bool run = false)
{
if (run) Reset();
}
void Reset()
{
_start = high_resolution_clock::now();
}
milliseconds Elapsed() const
{
return std::chrono::duration_cast<milliseconds>(high_resolution_clock::now() - _start);
}
private:
high_resolution_clock::time_point _start;
};
// Timer code end
// Cmd redirection code start
/*
//
//Credit goes to some guys from StackOverflow for directions and Randor from CodeProject for base code
//
*/
struct _JOBWRAPPER
{
HANDLE hJob;
_JOBWRAPPER() : hJob(NULL) {}
~_JOBWRAPPER() { if (this->hJob != NULL) CloseHandle(hJob); }
operator HANDLE() const { return this->hJob; }
}hJob;
typedef void(*TextOutFunction)(LPCSTR);
struct _THREADARGUMENTS
{
HANDLE hOutRead;
clock_t stTimeout;
LPCSTR pchBreakText;
TextOutFunction Function;
bool bGotInfo;
_THREADARGUMENTS() : bGotInfo(false), hOutRead(NULL), stTimeout(NULL), pchBreakText(nullptr), Function(nullptr) {}
};
void ReadCMDThread(_THREADARGUMENTS* Arguments)
{
if (Arguments->hOutRead != NULL)
{
UINT CheckForAnyResponseOnLoop = 5, CurrentLoop = 0;
clock_t ScanInterval = 50;
DWORD dwAvailable = 0;
DWORD bytesRead = 0;
CHAR szOut[4096] = { 0 };
if (Arguments->stTimeout == 0)
{
while (true)
{
CurrentLoop++;
PeekNamedPipe(Arguments->hOutRead, szOut, sizeof(szOut), &bytesRead, &dwAvailable, NULL);
if (0 != bytesRead)
{
if (ReadFile(Arguments->hOutRead, szOut, sizeof(szOut), &bytesRead, NULL))
Arguments->bGotInfo = true;
Arguments->Function(szOut);
if (Arguments->pchBreakText != nullptr && Arguments->pchBreakText != "" && strstr(szOut, Arguments->pchBreakText) != nullptr)
break;
memset(szOut, '\0', sizeof(char) * 4096);
}
if (CheckForAnyResponseOnLoop == CurrentLoop && Arguments->pchBreakText == "")
break;
std::this_thread::sleep_for((std::chrono::milliseconds)ScanInterval);
}
}
else
{
Timer timer(true);
while (timer.Elapsed() < (std::chrono::milliseconds)Arguments->stTimeout)
{
CurrentLoop++;
PeekNamedPipe(Arguments->hOutRead, szOut, sizeof(szOut), &bytesRead, &dwAvailable, NULL);
if (0 != bytesRead)
{
if (ReadFile(Arguments->hOutRead, szOut, sizeof(szOut), &bytesRead, NULL))
Arguments->bGotInfo = true;
Arguments->Function(szOut);
timer.Reset();
if (Arguments->pchBreakText != nullptr && Arguments->pchBreakText != "" && strstr(szOut, Arguments->pchBreakText) != nullptr)
break;
memset(szOut, '\0', sizeof(char) * 4096);
}
if (CheckForAnyResponseOnLoop == CurrentLoop && Arguments->pchBreakText == "")
break;
std::this_thread::sleep_for((std::chrono::milliseconds)ScanInterval);
}
}
}
}
class CMDREDIRECTION{
private:
HANDLE hInRead, hInWrite, hOutRead, hOutWrite;
PROCESS_INFORMATION pi;
STARTUPINFO si;
SECURITY_ATTRIBUTES sa;
TextOutFunction CustomFunction;
public:
CMDREDIRECTION(TextOutFunction Function) : hInRead(NULL), hInWrite(NULL), hOutRead(NULL),
hOutWrite(NULL), CustomFunction(Function) {}
~CMDREDIRECTION(){
if (hInRead != NULL)
CloseHandle(hInRead);
if (hInWrite != NULL)
CloseHandle(hInWrite);
if (hOutRead != NULL)
CloseHandle(hOutRead);
if (hOutWrite != NULL)
CloseHandle(hOutWrite);
}
DWORD WriteToCmd(LPSTR pchString, bool PressEnter = false)
{
DWORD dwWritten = 0;
size_t GivenStringLength = strlen(pchString);
LPSTR TemporaryString = pchString;
bool bSuccess = false;
if (GivenStringLength != 0)
{
if (PressEnter)
{
size_t StringSize = GivenStringLength + 2;
TemporaryString = new CHAR[StringSize];
for (size_t i = 0; i < GivenStringLength; i++)
TemporaryString[i] = pchString[i];
TemporaryString[StringSize - 2] = '\n';
TemporaryString[StringSize - 1] = '\0';
bSuccess = (WriteFile(hInWrite, TemporaryString, strlen(TemporaryString), &dwWritten, NULL) && dwWritten);
delete[] TemporaryString;
}
else
bSuccess = (WriteFile(hInWrite, TemporaryString, strlen(TemporaryString), &dwWritten, NULL) && dwWritten);
}
return bSuccess;
}
bool GetAnswer(clock_t stTimeout, LPCSTR pchBreakText)
{
_THREADARGUMENTS Arguments;
Arguments.hOutRead = hOutRead;
Arguments.pchBreakText = pchBreakText;
Arguments.stTimeout = stTimeout;
Arguments.Function = CustomFunction;
std::thread CMDWatcher(ReadCMDThread, &Arguments);
CMDWatcher.join();
return Arguments.bGotInfo;
}
bool WriteToCmdAndWaitForAnswer(LPSTR pchString, clock_t stTimeout, LPCSTR pchBreakText, bool PressEnter = false)
{
if (WriteToCmd(pchString, PressEnter))
{
return (GetAnswer(stTimeout, pchBreakText));
}
else
{
return false;
}
}
bool Start()
{
if (hJob.hJob == NULL)
{
hJob.hJob = CreateJobObject(NULL, NULL);
if (hJob.hJob != NULL)
{
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
if (!SetInformationJobObject((HANDLE)hJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)))
{
return false;
}
}
else
{
return false;
}
}
ZeroMemory(&sa, sizeof(sa));
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = TRUE;
CreatePipe(&hInRead, &hInWrite, &sa, 0);
CreatePipe(&hOutRead, &hOutWrite, &sa, 0);
ZeroMemory(&si, sizeof(si));
GetStartupInfo(&si);
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
si.hStdOutput = hOutWrite;
si.hStdError = hOutWrite;
si.hStdInput = hInRead;
si.wShowWindow = SW_HIDE;
TCHAR Path[MAX_PATH] = { 0 };
GetSystemDirectory(Path, MAX_PATH);
_tcscat_s(Path, TEXT("\\cmd.exe"));
if (CreateProcess(Path, NULL, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi))
{
BOOL bResult = AssignProcessToJobObject(hJob, pi.hProcess);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return (bResult != 0);
}
else
{
return false;
}
}
};
// Cmd redirection code end
// TString code start
#ifdef UNICODE
#define TCat TCatW
#define TString _TString<WCHAR>
#else
#define TCat TCatA
#define TString _TString<CHAR>
#endif
struct AnyString
{
PVOID String;
bool bWide;
AnyString(LPSTR String)
{
this->String = String;
bWide = false;
}
AnyString(LPWSTR String)
{
this->String = String;
bWide = true;
}
operator LPSTR() { return (LPSTR)String; }
operator LPSTR() const { return (LPSTR)String; }
operator LPWSTR() { return (LPWSTR)String; }
operator LPWSTR() const { return (LPWSTR)String; }
};
template<class T>
class _TString
{
friend void SeAnyString(LPSTR String, _TString<CHAR> &TempString);
T *String;
size_t size;
void free()
{
if (String != nullptr && size != 0)
{
delete[] String;
String = nullptr;
size = 0;
}
}
_TString<CHAR> ToCHAR(LPWSTR wch)
{
_TString<CHAR> TempString;
LPSTR Buffer = nullptr;
size_t size = wcslen(wch),
realsize = size + 1;
if (size != 0)
{
Buffer = new CHAR[realsize];
wcstombs_s(nullptr, Buffer, realsize, wch, size);
TempString.SetAllocatedString(Buffer, size);
}
return TempString;
}
_TString<WCHAR> ToWCHAR(LPSTR ch)
{
_TString<WCHAR> TempString;
LPWSTR Buffer = nullptr;
size_t size = strlen(ch),
realsize = size + 1;
if (size != 0)
{
Buffer = new WCHAR[realsize];
mbstowcs_s(nullptr, Buffer, realsize, ch, size);
TempString.SetAllocatedString(Buffer, size);
}
return TempString;
}
public:
_TString(T *String)
{
free();
if (typeid(T) == typeid(CHAR))
{
size = strlen(String);
if (size != 0)
{
this->String = new T[size + 1];
for (size_t i = 0; i < size; i++)
this->String[i] = String[i];
this->String[size] = '\0';
}
}
else if (typeid(T) == typeid(WCHAR))
{
size = wcslen(String);
if (size != 0)
{
this->String = new T[size + 1];
for (size_t i = 0; i < size; i++)
this->String[i] = String[i];
this->String[size] = L'\0';
}
}
}
_TString() : String(nullptr), size(0) {}
~_TString() { free(); }
_TString(_TString&& OldTempStr)
{
this->String = OldTempStr.String;
this->size = OldTempStr.size;
OldTempStr.size = 0;
OldTempStr.String = nullptr;
}
_TString& operator=(_TString&& OldTempStr)
{
this->String = OldTempStr.String;
this->size = OldTempStr.size;
OldTempStr.size = 0;
OldTempStr.String = nullptr;
return *this;
}
operator T*() const { return String; }
operator T*() { return String; }
T& operator[] (size_t i) { return String[i]; }
void SetAllocatedString(T *String, size_t size)
{
free();
this->String = String;
this->size = size;
}
void join(LPWSTR StringToJoin)
{
join(AnyString(StringToJoin));
}
void join(LPSTR StringToJoin)
{
join(AnyString(StringToJoin));
}
void join(AnyString StringToJoin)
{
if (typeid(T) == typeid(CHAR))
{
size_t length = 0;
_TString<CHAR> TempString;
LPSTR StringLiteral = nullptr;
if (StringToJoin.bWide)
{
TempString = ToCHAR(StringToJoin);
StringLiteral = TempString;
}
else
{
StringLiteral = StringToJoin;
}
if (StringLiteral != nullptr)
length = strlen(StringLiteral);
if (length != 0)
{
size_t newsize = size + length, realsize = newsize + 1;
T *Buffer = new T[realsize];
for (size_t i = 0; i < size; i++)
Buffer[i] = String[i];
for (size_t i = size, j = 0; i < newsize; i++, j++)
Buffer[i] = StringLiteral[j];
Buffer[newsize] = '\0';
free();
size = newsize;
String = Buffer;
}
}
else if (typeid(T) == typeid(WCHAR))
{
size_t length = 0;
_TString<WCHAR> TempString;
LPWSTR StringLiteral = nullptr;
if (StringToJoin.bWide)
{
StringLiteral = StringToJoin;
}
else
{
TempString = ToWCHAR(StringToJoin);
StringLiteral = TempString;
}
if (StringLiteral != nullptr)
length = wcslen(StringLiteral);
if (length != 0)
{
size_t newsize = size + length, realsize = newsize + 1;
T *Buffer = new T[realsize];
for (size_t i = 0; i < size; i++)
Buffer[i] = String[i];
for (size_t i = size, j = 0; i < newsize; i++, j++)
Buffer[i] = StringLiteral[j];
Buffer[newsize] = L'\0';
free();
size = newsize;
String = Buffer;
}
}
}
size_t GetSize() { return size; }
T* GetString() { return String; }
};
_TString<CHAR> TCatA(std::initializer_list<AnyString> list)
{
_TString<CHAR> String;
for (auto iterator = list.begin(), end = list.end(); iterator != end; ++iterator)
String.join(*iterator);
return String;
}
_TString<WCHAR> TCatW(std::initializer_list<AnyString> list)
{
_TString<WCHAR> String;
for (auto iterator = list.begin(), end = list.end(); iterator != end; ++iterator)
String.join(*iterator);
return String;
}
// TString code end
// Main code start
#define EXTENSION_NAME YOUR_EXTENSION_NAME //"my-extension" in ANSI
void WriteToOutputWindow(LPCSTR Text) { OutputDebugStringA(Text); }
void GetProjectDirectory(TString &Path)
{
TCHAR MaxPath[MAX_PATH] = { 0 };
GetModuleFileName(NULL, MaxPath, MAX_PATH);
for (int i = _tcslen(MaxPath), ch = 0; i > 0; i--)
{
if (MaxPath[i] == TEXT('\\') && ++ch == 2)
break;
else
MaxPath[i] = TEXT('\0');
}
Path.join(MaxPath);
}
void GetDataDirectory(TString &Path)
{
GetProjectDirectory(Path);
TCHAR TempBuffer[MAX_PATH] = { 0 }, FinalBuffer[MAX_PATH] = { 0 };
for (size_t i = Path.GetSize() - 1, ch = 0, j = 0; i > 0; i--, j++)
{
if (Path[i] == TEXT('\\') && ++ch == 2)
break;
else
TempBuffer[j] = Path[i];
}
for (size_t i = _tcslen(TempBuffer), j = 0; i > 0; i--, j++)
FinalBuffer[j] = TempBuffer[i - 1];
Path.join(FinalBuffer);
}
bool Restart()
{
int msgboxID = MessageBox(NULL, TEXT("Firefox has been closed. Save changes and press \"Yes\" to run again."), TEXT("Run again?"), MB_YESNO | MB_ICONQUESTION);
switch (msgboxID)
{
case IDYES:
return true;
case IDNO:
return false;
}
}
int WINAPI _tWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrev, _In_ LPTSTR lpCmdLine, _In_ int nCmdShow)
{
CMDREDIRECTION Window(WriteToOutputWindow);
TString ExtensionDir;
TString DataDir;
if (Window.Start())
{
GetProjectDirectory(ExtensionDir);
GetDataDirectory(DataDir);
ExtensionDir.join(TEXT("Firefox SDK\\"));
if (!PathIsDirectory(ExtensionDir))
Window.WriteToCmdAndWaitForAnswer(TCatA({ "mkdir \"", ExtensionDir.GetString(), "\"" }), 0, "", true);
if (PathIsDirectoryEmpty(ExtensionDir))
{
MessageBox(NULL, TCat({ TEXT("Firefox SDK directory is empty, please copy SDK files to this directory: "), ExtensionDir.GetString() }), TEXT("Failure!"), MB_ICONINFORMATION);
return EXIT_FAILURE;
}
Window.WriteToCmdAndWaitForAnswer(TCatA({ "cd ", ExtensionDir.GetString() }), 0, "", true);
Window.WriteToCmdAndWaitForAnswer("bin\\activate", 0, "", true);
ExtensionDir.join(TCat({ TEXT(EXTENSION_NAME), TEXT("\\") }));
if (!PathIsDirectory(ExtensionDir))
Window.WriteToCmdAndWaitForAnswer(TCatA({ "mkdir ", EXTENSION_NAME }), 0, "", true);
Window.WriteToCmdAndWaitForAnswer(TCatA({ "cd ", EXTENSION_NAME }), 0, "", true);
if (PathIsDirectoryEmpty(ExtensionDir))
Window.WriteToCmdAndWaitForAnswer("cfx init", 0, "", true);
do
{
/*
Window.WriteToCmdAndWaitForAnswer(TCatA({ "cd ", DataDir.GetString() }), 0, "", true);
Window.WriteToCmdAndWaitForAnswer(TCatA({ "XCOPY \"main.js\" \"", ExtensionDir.GetString(), TEXT(EXTENSION_NAME), "\\lib\\\" /Y" }), 0, "", true);
Window.WriteToCmdAndWaitForAnswer(TCatA({ "XCOPY \"*.js\" \"", ExtensionDir.GetString(), TEXT(EXTENSION_NAME), "\\data\\\" /Y /EXCLUDE:exclude.txt" }), 0, "", true);
Window.WriteToCmdAndWaitForAnswer(TCatA({ "XCOPY \"*.html\" \"", ExtensionDir.GetString(), TEXT(EXTENSION_NAME), "\\data\\\" /Y" }), 0, "", true);
Window.WriteToCmdAndWaitForAnswer(TCatA({ "XCOPY \"*.png\" \"", ExtensionDir.GetString(), TEXT(EXTENSION_NAME), "\\data\\\" /Y" }), 0, "", true);
Window.WriteToCmdAndWaitForAnswer(TCatA({ "XCOPY \"*.css\" \"", ExtensionDir.GetString(), TEXT(EXTENSION_NAME), "\\data\\\" /Y" }), 0, "", true);
*/
Window.WriteToCmdAndWaitForAnswer("cfx run --profiledir=\"./dir\"", 0, "Program terminated successfully.", true);
} while (Restart());
}
return EXIT_SUCCESS;
}
// Main code end
A client application has to access certificate from Windows certificate store. The search
input is the subject name in X500 string format as below.
"C=CH, S=Aargau, L=Baden, O=Test, OU=FF, CN= Test Root"
An exact match is required (not substring match using CERT_FIND_SUBJECT_STR).
For this i do the following
CERT_NAME_BLOB subjectname = {0};
/*convert the input X500 string to encoded subject name*/
bRet = CertStrToNameA(X509_ASN_ENCODING, "C=CH, S=Aargau, L=Baden, O=Test, OU=S1, CN= Test Root", CERT_X500_NAME_STR, NULL, NULL, &size, NULL);
if(TRUE == bRet)
{
subjectname.pbData = (BYTE*)malloc(size);
subjectname.cbData = size;
bRet = CertStrToNameA(X509_ASN_ENCODING , "C=CH, S=Aargau, L=Baden, O=Test, OU=S1, CN=Test Root", CERT_X500_NAME_STR, NULL, subjectname.pbData, &subjectname.cbData, NULL);
if(TRUE == bRet)
{
capiCertificate = CertFindCertificateInStore(hStore, X509_ASN_ENCODING, 0, CERT_FIND_SUBJECT_NAME, &subjectname, NULL);
if (NULL == capiCertificate)
{
errorcode = GetLastError();
ret = CA_CERT_NOT_FOUND;
}
}
}
The problem is that CertFindCertificateInStore always return NULL pointer. I have been debugging, but could not find out what is going wrong here.
Any suggestions will be very helpful.
In case anyone is looking for an answer to this question, i am posting how i could do it, incase it is useful
static PCCERT_CONTEXT
FindCertificate(
const HCERTSTORE hStore,
const char* CertSearchString)
{
PCCERT_CONTEXT capiCertificate = NULL;
DWORD dType = CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG;
char certname [MAX_SIZE_CERT_NAME] = {0};
for(;;)
{
capiCertificate = CertEnumCertificatesInStore(hStore, capiCertificate);
if (NULL == capiCertificate)
{
break;
}
if (FALSE ==
CertGetNameStringA(capiCertificate, CERT_NAME_RDN_TYPE,
0, &dType, certname, MAX_SIZE_CERT_NAME))
{
CertFreeCertificateContext(capiCertificate);
capiCertificate = NULL;
break;
}
if ((0 == strncmp(certname, CertSearchString, MAX_SIZE_CERT_NAME)) &&
(capiCertificate->dwCertEncodingType == X509_ASN_ENCODING))
{
break;
}
}
return capiCertificate;
}
I have a map that is acting up and not returning the correct number. It did then it didn't, now it's just not returning. Any help is appreciated. Thank you.
struct file_data
{
std::wstring sLastAccessTime;
__int64 nFileSize ;
};
int GetFileList(const wchar_t *searchkey, std::map<std::wstring, file_data> &map)
{
WIN32_FIND_DATA fd;
HANDLE h = FindFirstFile(searchkey,&fd);
if(h == INVALID_HANDLE_VALUE)
{
return 0; // no files found
}
while(1)
{
wchar_t buf[128];
FILETIME ft = fd.ftLastWriteTime;
SYSTEMTIME sysTime;
FileTimeToSystemTime(&ft, &sysTime);
wsprintf(buf, L"%d-%02d-%02d",sysTime.wYear, sysTime.wMonth, sysTime.wDay);
file_data filedata;
filedata.sLastAccessTime= buf;
filedata.nFileSize = (((__int64)fd.nFileSizeHigh) << 32) + fd.nFileSizeLow;
map[fd.cFileName]= filedata;
if (FindNextFile(h, &fd) == FALSE)
break;
}
return map.size();
}
int main()
{
std::map<std::wstring, file_data> map;
int count = GetFileList(L"C:\\Users\\DS\\Downloads\\*.pdf", map);
int count1 = GetFileList(L"C:\\Users\\DS\\Downloads\\*.txt", map);
int count2 = GetFileList(L"C:\\Users\\DS\\Downloads\\*.jpg", map);
for(std::map<std::wstring, file_data>::const_iterator it = map.begin(); it != map.end(); ++it)
{
if (count2 != 0)
{
printf("\n How Many: %i \n", count2);
}
else
{
printf ("%s \n", "Nothing");
}
return 0;
}
}
Note that GetFileList() returns the number of items in the map.
In your implementation it is cumulative. Maybe you want to clear the map between consecutive calls to GetFileList().
OK found the solution. This is it.
GetFileList(L"C:\\Users\\DS\\Downloads\\*.pdf", map);
GetFileList(L"C:\\Users\\DS\\Downloads\\*.txt", map);
GetFileList(L"C:\\Users\\DS\\Downloads\\*.jpg", map);
if( map.size() > 0
then...........
How do you resolve an NT style device path, e.g. \Device\CdRom0, to its logical drive letter, e.g. G:\ ?
Edit: A Volume Name isn't the same as a Device Path so unfortunately GetVolumePathNamesForVolumeName() won't work.
Hopefully the following piece of code will give you enough to solve this - after you've initialised it, you just need to iterate through the collection to find your match. You may want to convert everything to upper/lower case before you insert into the collection to help with lookup performance.
typedef basic_string<TCHAR> tstring;
typedef map<tstring, tstring> HardDiskCollection;
void Initialise( HardDiskCollection &_hardDiskCollection )
{
TCHAR tszLinkName[MAX_PATH] = { 0 };
TCHAR tszDevName[MAX_PATH] = { 0 };
TCHAR tcDrive = 0;
_tcscpy_s( tszLinkName, MAX_PATH, _T("a:") );
for ( tcDrive = _T('a'); tcDrive < _T('z'); ++tcDrive )
{
tszLinkName[0] = tcDrive;
if ( QueryDosDevice( tszLinkName, tszDevName, MAX_PATH ) )
{
_hardDiskCollection.insert( pair<tstring, tstring>( tszLinkName, tszDevName ) );
}
}
}
Maybe you could use GetVolumeNameForMountPoint and iterate through all mount points A:\ through Z:\, breaking when you find a match?
http://msdn.microsoft.com/en-us/library/aa364994(VS.85).aspx
(I haven't tried this)
Following function does the job using C only
BOOL GetWin32FileName(const TCHAR* pszNativeFileName, TCHAR *pszWin32FileName)
{
BOOL bFound = FALSE;
// Translate path with device name to drive letters.
TCHAR szTemp[MAX_PATH];
szTemp[0] = '\0';
if (GetLogicalDriveStrings(MAX_PATH - 1, szTemp))
{
TCHAR szName[MAX_PATH];
TCHAR szDrive[3] = TEXT(" :");
TCHAR* p = szTemp;
do
{
// Copy the drive letter to the template string
*szDrive = *p;
// Look up each device name
if (QueryDosDevice(szDrive, szName, MAX_PATH))
{
size_t uNameLen = _tcslen(szName);
if (uNameLen < MAX_PATH)
{
bFound = _tcsnicmp(pszNativeFileName, szName, uNameLen) == 0
&& *(pszNativeFileName + uNameLen) == _T('\\');
if (bFound)
{
// Replace device path with DOS path
StringCchPrintf(pszWin32FileName,
MAX_PATH,
TEXT("%s%s"),
szDrive,
pszNativeFileName + uNameLen);
}
}
}
// Go to the next NULL character.
while (*p++);
} while (!bFound && *p);
}
return(bFound);
}
You can lookup all volumes' name to match a device name and get drive letter.Here is a sample:
int DeviceNameToVolumePathName(WCHAR *filepath) {
WCHAR fileDevName[MAX_PATH];
WCHAR devName[MAX_PATH];
WCHAR fileName[MAX_PATH];
HANDLE FindHandle = INVALID_HANDLE_VALUE;
WCHAR VolumeName[MAX_PATH];
DWORD Error = ERROR_SUCCESS;
size_t Index = 0;
DWORD CharCount = MAX_PATH + 1;
int index = 0;
// \Device\HarddiskVolume1\windows,locate \windows.
for (int i = 0; i < lstrlenW(filepath); i++) {
if (!memcmp(&filepath[i], L"\\", 2)) {
index++;
if (index == 3) {
index = i;
break;
}
}
}
filepath[index] = L'\0';
memcpy(fileDevName, filepath, (index + 1) * sizeof(WCHAR));
FindHandle = FindFirstVolumeW(VolumeName, ARRAYSIZE(VolumeName));
if (FindHandle == INVALID_HANDLE_VALUE)
{
Error = GetLastError();
wprintf(L"FindFirstVolumeW failed with error code %d\n", Error);
return FALSE;
}
for (;;)
{
// Skip the \\?\ prefix and remove the trailing backslash.
Index = wcslen(VolumeName) - 1;
if (VolumeName[0] != L'\\' ||
VolumeName[1] != L'\\' ||
VolumeName[2] != L'?' ||
VolumeName[3] != L'\\' ||
VolumeName[Index] != L'\\')
{
Error = ERROR_BAD_PATHNAME;
wprintf(L"FindFirstVolumeW/FindNextVolumeW returned a bad path: %s\n", VolumeName);
break;
}
VolumeName[Index] = L'\0';
CharCount = QueryDosDeviceW(&VolumeName[4], devName, 100);
if (CharCount == 0)
{
Error = GetLastError();
wprintf(L"QueryDosDeviceW failed with error code %d\n", Error);
break;
}
if (!lstrcmpW(devName, filepath)) {
VolumeName[Index] = L'\\';
Error = GetVolumePathNamesForVolumeNameW(VolumeName, fileName, CharCount, &CharCount);
if (!Error) {
Error = GetLastError();
wprintf(L"GetVolumePathNamesForVolumeNameW failed with error code %d\n", Error);
break;
}
// concat drive letter to path
lstrcatW(fileName, &filepath[index + 1]);
lstrcpyW(filepath, fileName);
Error = ERROR_SUCCESS;
break;
}
Error = FindNextVolumeW(FindHandle, VolumeName, ARRAYSIZE(VolumeName));
if (!Error)
{
Error = GetLastError();
if (Error != ERROR_NO_MORE_FILES)
{
wprintf(L"FindNextVolumeW failed with error code %d\n", Error);
break;
}
//
// Finished iterating
// through all the volumes.
Error = ERROR_BAD_PATHNAME;
break;
}
}
FindVolumeClose(FindHandle);
if (Error != ERROR_SUCCESS)
return FALSE;
return TRUE;
}
If you want to resolve it in driver,you can check this link for reference.
Here is refactored version of the solution.
I replaced TChAR with wchar_t because afaik it's not a good idea to use it in most projects.
std::map<std::wstring, std::wstring> GetDosPathDevicePathMap()
{
// It's not really related to MAX_PATH, but I guess it should be enough.
// Though the docs say "The first null-terminated string stored into the buffer is the current mapping for the device.
// The other null-terminated strings represent undeleted prior mappings for the device."
wchar_t devicePath[MAX_PATH] = { 0 };
std::map<std::wstring, std::wstring> result;
std::wstring dosPath = L"A:";
for (wchar_t letter = L'A'; letter <= L'Z'; ++letter)
{
dosPath[0] = letter;
if (QueryDosDeviceW(dosPath.c_str(), devicePath, MAX_PATH)) // may want to properly handle errors instead ... e.g. check ERROR_INSUFFICIENT_BUFFER
{
result[dosPath] = devicePath;
}
}
return result;
}