changeset 260:e7a8b70021b6

Merged
author Sascha Wilde <wilde@intevation.de>
date Tue, 01 Apr 2014 15:46:40 +0200
parents 20d515604daa (current diff) 06089ba2614a (diff)
children 7707191ddb01
files common/CMakeLists.txt common/certhelp.c common/debug.h
diffstat 15 files changed, 402 insertions(+), 82 deletions(-) [+]
line wrap: on
line diff
--- 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 <sys/types.h>
 
 #define DEBUGPREFIX "MOZ-"
-#include "debug.h"
+#include "logging.h"
 
 #include "errorcodes.h"
 #include "portpath.h"
--- 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);
             }
         }
     }
--- 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
 )
--- 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 <stdlib.h>
 
 #include "certhelp.h"
-#include "debug.h"
+#include "logging.h"
 #include "errorcodes.h"
 #include "strhelp.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
--- /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 <stdio.h>
+
+#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
--- /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 <windows.h>
+
+/** @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 */
--- 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 <polarssl/base64.h>
 
+#ifdef WIN32
+#include <windows.h>
+#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
--- 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 <stdbool.h>
+#include <stddef.h>
 
 /**
  * @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
--- 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}
 )
--- 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 <QDateTime>
 #include <QObject>
 
-#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<Certificate> mCertificates;
     QString mData;
--- /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 <QFileInfo>
+#include <QTemporaryFile>
+#include <QApplication>
+#include <QDir>
+#include <QDebug>
+
+#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<LPCWSTR> (cinstFileName.utf16());
+    mExecInfo.lpParameters =  reinterpret_cast<LPCWSTR> (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
--- /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 <QString>
+#include <QStringList>
+#include <QProcess>
+#include <QThread>
+
+#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
--- 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 <QListWidget>
 #include <QVBoxLayout>
 #include <QLabel>
+#include <QMessageBox>
+
+
 #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)
--- 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*);
 };

http://wald.intevation.org/projects/trustbridge/