# HG changeset patch # User Sascha Wilde # Date 1396360000 -7200 # Node ID e7a8b70021b63cc932e3d873a53f8bd1f9be16bf # Parent 20d515604daa3a30e6a81d8a1609d0bd208e4235# Parent 06089ba2614abe125784b68c12c9977ba2fb9a7a Merged diff -r 20d515604daa -r e7a8b70021b6 cinst/mozilla.c --- a/cinst/mozilla.c Tue Apr 01 15:41:11 2014 +0200 +++ b/cinst/mozilla.c Tue Apr 01 15:46:40 2014 +0200 @@ -55,7 +55,7 @@ #include #define DEBUGPREFIX "MOZ-" -#include "debug.h" +#include "logging.h" #include "errorcodes.h" #include "portpath.h" diff -r 20d515604daa -r e7a8b70021b6 cinst/windowsstore.c --- a/cinst/windowsstore.c Tue Apr 01 15:41:11 2014 +0200 +++ b/cinst/windowsstore.c Tue Apr 01 15:46:40 2014 +0200 @@ -6,32 +6,7 @@ #include "errorcodes.h" #include "listutil.h" #include "strhelp.h" - -static LPWSTR -getLastErrorMsg() -{ - LPWSTR bufPtr = NULL; - DWORD err = GetLastError(); - FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, err, 0, (LPWSTR) &bufPtr, 0, NULL); - if (!bufPtr) - { - HMODULE hWinhttp = GetModuleHandleW (L"crypt32"); - if (hWinhttp) - { - FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_HMODULE | - FORMAT_MESSAGE_IGNORE_INSERTS, - hWinhttp, HRESULT_CODE (err), 0, - (LPWSTR) &bufPtr, 0, NULL); - } - } - if (!bufPtr) - printf ("Error getting last error for code: %lx \n", err); - return bufPtr; -} +#include "logging.h" static PCCERT_CONTEXT b64_to_cert_context(char *b64_data, size_t b64_size) @@ -59,11 +34,11 @@ if (pCert == NULL) { - LPWSTR error = getLastErrorMsg(); + char *error = getLastErrorMsg(); if (error) { - printf ("Failed to create cert context: %S \n", error); - LocalFree (error); + printf ("Failed to create cert context: %s \n", error); + free (error); } return NULL; } @@ -90,11 +65,11 @@ if (pc_to_remove == NULL) { - LPWSTR error = getLastErrorMsg(); + char *error = getLastErrorMsg(); if (error) { - printf ("Failed to create cert context: %S \n", error); - LocalFree (error); + printf ("Failed to create cert context: %s \n", error); + free (error); } continue; } @@ -120,9 +95,9 @@ The CertDeleteCertificateFromStore function always frees pCertContext by calling the CertFreeCertificateContext function, even if an error is encountered. */ - LPWSTR error = getLastErrorMsg(); - printf ("Error deleting certificate. %S", error); - LocalFree (error); + char *error = getLastErrorMsg(); + printf ("Error deleting certificate. %s", error); + free (error); continue; } } @@ -174,11 +149,11 @@ CertFreeCertificateContext (pc_to_add); if (!ret) { - LPWSTR error = getLastErrorMsg(); + char *error = getLastErrorMsg(); if (error) { - printf ("Failed to add certificate: %S \n", error); - LocalFree (error); + printf ("Failed to add certificate: %s \n", error); + free (error); } } } diff -r 20d515604daa -r e7a8b70021b6 common/CMakeLists.txt --- a/common/CMakeLists.txt Tue Apr 01 15:41:11 2014 +0200 +++ b/common/CMakeLists.txt Tue Apr 01 15:46:40 2014 +0200 @@ -1,6 +1,7 @@ set (m13_common_src certhelp.c listutil.c + logging.c portpath.c strhelp.c ) diff -r 20d515604daa -r e7a8b70021b6 common/certhelp.c --- a/common/certhelp.c Tue Apr 01 15:41:11 2014 +0200 +++ b/common/certhelp.c Tue Apr 01 15:46:40 2014 +0200 @@ -1,7 +1,7 @@ #include #include "certhelp.h" -#include "debug.h" +#include "logging.h" #include "errorcodes.h" #include "strhelp.h" diff -r 20d515604daa -r e7a8b70021b6 common/debug.h --- a/common/debug.h Tue Apr 01 15:41:11 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -#ifndef DEBUG_H -#define DEBUG_H - -/** - * @file - * @brief Helper macros for debugging - */ - -/** - * @def DEBUGOUTPUT - * @brief If defined code for extra debugging output will be generated. - * - * Will be defined if current build is not an RELEASE_BUILD. - */ -#ifndef RELEASE_BUILD -#define DEBUGOUTPUT -#endif - -/** - * @def DEBUGPREFIX - * @brief A string prepended to debug output. - * - * Should be defined to indicate which module created the output. - */ -#ifndef DEBUGPREFIX -#define DEBUGPREFIX "" -#endif - -/** - * @def DEBUGPRINTF(fmt, ...) - * @brief Debug printf - * - * Prints to stderr if DEBUGOUTPUT is defined. - */ -#ifdef DEBUGOUTPUT -#define DEBUGPRINTF(fmt, ...) fprintf(stderr, DEBUGPREFIX "DEBUG: " fmt, ##__VA_ARGS__); -#else -#define DEBUGPRINTF(fmt, ...) -#endif - -#endif diff -r 20d515604daa -r e7a8b70021b6 common/logging.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/logging.c Tue Apr 01 15:46:40 2014 +0200 @@ -0,0 +1,40 @@ +#include "logging.h" +#include "strhelp.h" + +#include + +#ifdef WIN32 +char * +getLastErrorMsg() +{ + LPWSTR bufPtr = NULL; + DWORD err = GetLastError(); + char *retval = NULL; + FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, err, 0, (LPWSTR) &bufPtr, 0, NULL); + if (!bufPtr) + { + HMODULE hWinhttp = GetModuleHandleW (L"crypt32"); + if (hWinhttp) + { + FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_HMODULE | + FORMAT_MESSAGE_IGNORE_INSERTS, + hWinhttp, HRESULT_CODE (err), 0, + (LPWSTR) &bufPtr, 0, NULL); + } + } + if (!bufPtr) { + fprintf (stderr, "Error getting last error for code: %lx \n", err); + return NULL; + } + + retval = wchar_to_utf8(bufPtr, wcslen(bufPtr)); + LocalFree (bufPtr); + + return retval; +} + +#endif diff -r 20d515604daa -r e7a8b70021b6 common/logging.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/logging.h Tue Apr 01 15:46:40 2014 +0200 @@ -0,0 +1,63 @@ +#ifndef COMMON_LOGGING_H +#define COMMON_LOGGING_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * @file + * @brief Logging and debugging functions + */ + +#ifdef WIN32 + +#include + +/** @brief Gets the localized error message for the last error + * returned by GetLastError + * + * @returns utf8 error message that needs to be freed by the caller. + **/ + +char *getLastErrorMsg(); + +#endif + +/** + * @def DEBUGOUTPUT + * @brief If defined code for extra debugging output will be generated. + * + * Will be defined if current build is not an RELEASE_BUILD. + */ +#ifndef RELEASE_BUILD +#define DEBUGOUTPUT +#endif + +/** + * @def DEBUGPREFIX + * @brief A string prepended to debug output. + * + * Should be defined to indicate which module created the output. + */ +#ifndef DEBUGPREFIX +#define DEBUGPREFIX "" +#endif + +/** + * @def DEBUGPRINTF(fmt, ...) + * @brief Debug printf + * + * Prints to stderr if DEBUGOUTPUT is defined. + */ +#ifdef DEBUGOUTPUT +#define DEBUGPRINTF(fmt, ...) fprintf(stderr, DEBUGPREFIX "DEBUG: " fmt, ##__VA_ARGS__); +#else +#define DEBUGPRINTF(fmt, ...) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* COMMON_LOGGING_H */ diff -r 20d515604daa -r e7a8b70021b6 common/strhelp.c --- a/common/strhelp.c Tue Apr 01 15:41:11 2014 +0200 +++ b/common/strhelp.c Tue Apr 01 15:46:40 2014 +0200 @@ -7,6 +7,10 @@ #include +#ifdef WIN32 +#include +#endif + /* Remarks regarding the "Flawfinder: ignore" comments in this file: * * - strlen: @@ -182,3 +186,65 @@ } return ret; } + +void +xfree (void *p) +{ + if (p) + free (p); +} + +#ifdef WIN32 +/* Adapted from GPGOL rev. e512053 */ +char * +wchar_to_utf8 (const wchar_t *string, size_t len) +{ + int n, ilen; + char *result; + + ilen = (int) len; + if (ilen < 0) + return NULL; + + /* Note, that CP_UTF8 is not defined in Windows versions earlier + than NT.*/ + n = WideCharToMultiByte (CP_UTF8, 0, string, ilen, NULL, 0, NULL, NULL); + if (n < 0) + return NULL; + + result = xmalloc ((size_t)n+1); + n = WideCharToMultiByte (CP_UTF8, 0, string, ilen, result, n, NULL, NULL); + if (n < 0) + { + xfree (result); + return NULL; + } + return result; +} + +/* Adapted from GPGOL rev. e512053 */ +wchar_t * +utf8_to_wchar (const char *string, size_t len) +{ + int n, ilen; + wchar_t *result; + + ilen = (int) len; + if (ilen < 0) + return NULL; + + n = MultiByteToWideChar (CP_UTF8, 0, string, ilen, NULL, 0); + if (n < 0 || n + 1 < 0) + return NULL; + + result = xmalloc ((size_t)(n+1) * sizeof *result); + n = MultiByteToWideChar (CP_UTF8, 0, string, ilen, result, n); + if (n < 0) + { + xfree (result); + return NULL; + } + result[n] = 0; + return result; +} +#endif diff -r 20d515604daa -r e7a8b70021b6 common/strhelp.h --- a/common/strhelp.h Tue Apr 01 15:41:11 2014 +0200 +++ b/common/strhelp.h Tue Apr 01 15:46:40 2014 +0200 @@ -6,6 +6,7 @@ #endif #include +#include /** * @file strhelp.h @@ -19,6 +20,7 @@ void *xrealloc( void *a, size_t n ); void *xcalloc( size_t n, size_t m ); char *xstrndup( const char *string, const size_t len ); +void xfree ( void *p ); /** * @brief Returns the length of the given %NULL-terminated @@ -101,6 +103,30 @@ */ int str_base64_decode(char **dst, size_t *dst_size, char *src, size_t src_size); + +#ifdef WIN32 + +/** @brief convert a utf8 string to utf16 wchar + * + * @param[in] string utf8 string. Must be at least len characters long. + * @param[in] len number of characters to be converted. + * + * @returns pointer to a newly allocated wchar array. NULL on error. + * + **/ +wchar_t *utf8_to_wchar (const char *string, size_t len); + +/** @brief convert a utf16 string to utf8 + * + * @param[in] string utf16 string. Must be at least len characters long. + * @param[in] len number of characters to be converted. + * + * @returns pointer to a newly allocated char array. NULL on error. + * + **/ +char *wchar_to_utf8 (const wchar_t *string, size_t len); +#endif + #ifdef __cplusplus } #endif diff -r 20d515604daa -r e7a8b70021b6 ui/CMakeLists.txt --- a/ui/CMakeLists.txt Tue Apr 01 15:41:11 2014 +0200 +++ b/ui/CMakeLists.txt Tue Apr 01 15:46:40 2014 +0200 @@ -1,5 +1,6 @@ include_directories(${Qt5Widgets_INCLUDE_DIRS}) include_directories(${POLARSSL_INCLUDE_DIR}) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../common) add_definitions(${Qt5Widgets_DEFINITIONS}) set(CERTIFICATELIST_SOURCES @@ -19,6 +20,7 @@ ${CMAKE_CURRENT_SOURCE_DIR}/helpdialog.cpp ${CMAKE_CURRENT_SOURCE_DIR}/aboutdialog.cpp ${CMAKE_CURRENT_SOURCE_DIR}/statusdialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/installwrapper.cpp ${CERTIFICATELIST_SOURCES} ${DOWNLOADER_SOURCES} ) diff -r 20d515604daa -r e7a8b70021b6 ui/certificatelist.h --- a/ui/certificatelist.h Tue Apr 01 15:41:11 2014 +0200 +++ b/ui/certificatelist.h Tue Apr 01 15:46:40 2014 +0200 @@ -18,7 +18,7 @@ #include #include -#include "../common/listutil.h" +#include "listutil.h" #include "certificate.h" class CertificateList @@ -50,6 +50,9 @@ /* @brief get the raw certificate list */ const QString& rawData() const {return mData;} + /* @brief get the absolute filename of the certificate */ + const QString& fileName() const {return mFileName;} + private: QList mCertificates; QString mData; diff -r 20d515604daa -r e7a8b70021b6 ui/installwrapper.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/installwrapper.cpp Tue Apr 01 15:46:40 2014 +0200 @@ -0,0 +1,87 @@ +#include "installwrapper.h" + +#include +#include +#include +#include +#include + +#include "logging.h" + +InstallWrapper::InstallWrapper(QObject* parent, + const QString& path, const QStringList& instructions): + QThread(parent), + mCertListFile(path), + mInstructions(instructions) +{ +} + +QFileInfo getCinstProcInfo() { + QFileInfo fi(QCoreApplication::applicationFilePath()); + QDir myDir = fi.absoluteDir(); + QString instProcName = "cinst"; + if (!fi.suffix().isEmpty()) { + instProcName += "." + fi.suffix(); + } + return QFileInfo(myDir.absoluteFilePath(instProcName)); +} + +#ifdef WIN32 +extern Q_CORE_EXPORT int qt_ntfs_permission_lookup; + +void InstallWrapper::run() +{ + QTemporaryFile instructionsFile; + QFileInfo cinstProcInfo = getCinstProcInfo(); + + QString cinstFileName = QDir::toNativeSeparators( + getCinstProcInfo().absoluteFilePath()); + + if (!cinstProcInfo.isExecutable()) { + emit error (tr("Could not find certificate installation process.")); + return; + } + + instructionsFile.open(); + + qt_ntfs_permission_lookup++; + if (instructionsFile.permissions() ^ ( + QFileDevice::ReadUser | + QFileDevice::WriteUser | + QFileDevice::ReadOwner | + QFileDevice::WriteOwner)) { + emit error (tr("Invalid permissions on temporary file.")); + } + + foreach (const QString &b64data, mInstructions) { + instructionsFile.write(b64data.toLatin1()); + instructionsFile.write("\n"); + } + + instructionsFile.close(); + + QString parameters = "\"" + mCertListFile + "\" \"" +instructionsFile.fileName() + "\""; + + memset (&mExecInfo, 0, sizeof(SHELLEXECUTEINFOW)); + mExecInfo.cbSize = sizeof(SHELLEXECUTEINFOW); + mExecInfo.fMask = SEE_MASK_FLAG_NO_UI | + SEE_MASK_NOASYNC; + mExecInfo.lpVerb = L"runas"; + mExecInfo.lpFile = reinterpret_cast (cinstFileName.utf16()); + mExecInfo.lpParameters = reinterpret_cast (parameters.utf16()); + + qDebug() << "Starting process " << cinstFileName <<" params: " << parameters; + + if (!ShellExecuteExW(&mExecInfo)) { + char* errmsg = getLastErrorMsg(); + QString qerrmsg = QString::fromUtf8(errmsg); + free(errmsg); + emit(tr("Error executing process: %1").arg(qerrmsg)); + } + qt_ntfs_permission_lookup--; +} +#else +void InstallWrapper::run() +{ +} +#endif diff -r 20d515604daa -r e7a8b70021b6 ui/installwrapper.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/installwrapper.h Tue Apr 01 15:46:40 2014 +0200 @@ -0,0 +1,66 @@ +#ifndef UI_INSTALLWRAPPER_H +#define UI_INSTALLWRAPPER_H + +#include +#include +#include +#include + +#include "certificate.h" +/** @file installwrapper.h + * @brief Wrapper around the call to the updated process */ + + /** @brief wrapper around installer process + * + * This wrapper is mostly needed because QProcess executes + * a process on Windows directly with CreateProcess and + * thus can not be used to elevate the Process. + * + * On Windows this class uses ShellExecuteExW to control + * the child process. On Linux systems QProcess is used. + * + * It subclasses QThread so the installation can be done + * asynchronusly. */ +class InstallWrapper : public QThread +{ + Q_OBJECT + +public: + /** + * @brief Construct an installwrapper for a certificateList + * + * The install wrapper will start the cinst process to execute + * the specified instructions with the provided certificatelist. + * + * The cinst executable is expected to be in the same directory + * as the current application. + * + * @param[in] parent the parent object. + * @param[in] listFileName the absolute path to the certificatelist. + * @param[in] instructions a list of instructions to execute. + */ + InstallWrapper(QObject* parent, const QString& path, + const QStringList& instructions); + +private: + const QString mCertListFile; + const QStringList mInstructions; +#ifdef WIN32 + SHELLEXECUTEINFOW mExecInfo; +#else + QProcess cinstProc; +#endif + +protected: + void run(); + +Q_SIGNALS: + /** + * @brief An error happened + * + * @param[out] message: A localized message to show. Can be empty. + */ + void error(const QString &message); +}; + +#endif // UI_INSTALLWRAPPER_H diff -r 20d515604daa -r e7a8b70021b6 ui/listupdatedialog.cpp --- a/ui/listupdatedialog.cpp Tue Apr 01 15:41:11 2014 +0200 +++ b/ui/listupdatedialog.cpp Tue Apr 01 15:46:40 2014 +0200 @@ -10,7 +10,11 @@ #include #include #include +#include + + #include "certificate.h" +#include "installwrapper.h" ListUpdateDialog::ListUpdateDialog(QMainWindow *parent, const CertificateList &listToInstall) : @@ -86,7 +90,33 @@ return; } +void ListUpdateDialog::installerError(const QString& errMsg) { + QMessageBox::warning(this, tr("Installation Error"), errMsg); +} + void ListUpdateDialog::executeUpdate() { + + QStringList instructions; + + for (int i = 0; i < mCertListWidget->count(); i++) { + QListWidgetItem *item = mCertListWidget->item(i); + if (item->checkState() == Qt::Checked) { + instructions << item->data(Qt::UserRole).toString(); + } + + /* TODO: Check if it was an install instruction for an old certificate + * (already installed) and remove it in case it is unchecked. */ + } + + InstallWrapper *instWrap = new InstallWrapper(this, + mCertificateList.fileName(), + instructions); + connect(instWrap, SIGNAL(finished()), instWrap, SLOT(deleteLater())); + connect(instWrap, SIGNAL(error(const QString &)), + this, SLOT(installerError(const QString &))); + instWrap->start(); + +#if 0 /* TODO move this in another dialog and call it async*/ QProcess installerProcess; QFileInfo fi(QCoreApplication::applicationFilePath()); @@ -155,6 +185,7 @@ qDebug() << "output: " << installerProcess.readAllStandardOutput(); return; } +#endif } void ListUpdateDialog::showDetails(QListWidgetItem *item) diff -r 20d515604daa -r e7a8b70021b6 ui/listupdatedialog.h --- a/ui/listupdatedialog.h Tue Apr 01 15:41:11 2014 +0200 +++ b/ui/listupdatedialog.h Tue Apr 01 15:46:40 2014 +0200 @@ -28,6 +28,7 @@ QTextEdit *mDetailWidget; private slots: + void installerError(const QString& errMsg); void executeUpdate(); void showDetails(QListWidgetItem*); };