changeset 1118:fd85a02d771d

(issue54) Implement a privilege drop to execute the program after installation. This commit is extremly ugly as I accidentally worked in a working tree that was partially merged with default. To review the real change please check the commit that will merge this branch into default.
author Andre Heinecke <andre.heinecke@intevation.de>
date Tue, 16 Sep 2014 19:45:19 +0200
parents 5b6203f78b4e (current diff) 1c1964c27b39 (diff)
children 5349e2354c48
files CMakeLists.txt cinst/nssstore_win.c common/util.c common/util.h packaging/CMakeLists.txt packaging/desktopshellrun.cpp packaging/exdll.h packaging/trustbridge.nsi packaging/win-createpackage.sh.in
diffstat 10 files changed, 488 insertions(+), 78 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Tue Sep 16 11:45:32 2014 +0200
+++ b/CMakeLists.txt	Tue Sep 16 19:45:19 2014 +0200
@@ -153,12 +153,7 @@
    add_subdirectory(manuals)
 endif()
 
-# Configure packaging script for testing
-configure_file (packaging/win-createpackage.sh.in packaging/win-createpackage.sh @ONLY)
-configure_file (packaging/create-dist-package.sh.in packaging/create-dist-package.sh @ONLY)
-configure_file (packaging/linux-createpackage.sh.in packaging/linux-createpackage.sh @ONLY)
-configure_file (packaging/linux-installer.inc.in packaging/linux-installer.inc @ONLY)
-configure_file (packaging/linux-installer.l10n-de packaging/linux-installer.l10n-de COPYONLY)
+add_subdirectory(packaging)
 
 if (ENABLE_PROFILING)
    configure_file (make-coverage.sh.in make-coverage.sh)
--- a/cinst/nssstore_win.c	Tue Sep 16 11:45:32 2014 +0200
+++ b/cinst/nssstore_win.c	Tue Sep 16 19:45:19 2014 +0200
@@ -39,7 +39,6 @@
 */
 
 #include <windows.h>
-#include <winsafer.h>
 #include <sddl.h>
 #include <stdio.h>
 #include <stdbool.h>
@@ -99,73 +98,6 @@
   xfree (item);
 }
 
-/** @brief get a restricted access token to execute nss process
-  *
-  * This function uses the Software Restriction API to obtain the
-  * access token for a process run als normal user.
-  *
-  * @returns A restricted handle or NULL on error.
-  */
-static HANDLE
-get_restricted_token()
-{
-  SAFER_LEVEL_HANDLE user_level = NULL;
-  HANDLE retval = NULL;
-  SID_IDENTIFIER_AUTHORITY medium_identifier = {SECURITY_MANDATORY_LABEL_AUTHORITY};
-  PSID medium_sid = NULL;
-  TOKEN_MANDATORY_LABEL integrity_label;
-
-  memset (&integrity_label, 0, sizeof (integrity_label));
-
-  if (!SaferCreateLevel(SAFER_SCOPEID_USER,
-                        SAFER_LEVELID_NORMALUSER,
-                        SAFER_LEVEL_OPEN, &user_level, NULL))
-    {
-      PRINTLASTERROR ("Failed to create user level.\n");
-      return NULL;
-    }
-
-  if (!SaferComputeTokenFromLevel(user_level, NULL, &retval, 0, NULL))
-    {
-      SaferCloseLevel(user_level);
-      return NULL;
-    }
-
-  SaferCloseLevel(user_level);
-
-  /* Set the SID to medium it will still be high otherwise. Even if
-  there is no high access allowed. */
-  if (!AllocateAndInitializeSid(&medium_identifier,
-                               1,
-                               SECURITY_MANDATORY_MEDIUM_RID,
-                               0,
-                               0,
-                               0,
-                               0,
-                               0,
-                               0,
-                               0,
-                               &medium_sid))
-    {
-      PRINTLASTERROR ("Failed to initialize sid.\n");
-      return NULL;
-    }
-
-  integrity_label.Label.Attributes = SE_GROUP_INTEGRITY;
-  integrity_label.Label.Sid        = medium_sid;
-
-  if (!SetTokenInformation(retval,
-                           TokenIntegrityLevel,
-                           &integrity_label,
-                           sizeof(TOKEN_MANDATORY_LABEL)))
-    {
-      PRINTLASTERROR ("Failed to set token integrity.\n");
-      return NULL;
-    }
-
-  return retval;
-}
-
 /**@brief Write strv of instructions to a handle
 *
 * Writes the null terminated list of instructions to
--- a/common/util.c	Tue Sep 16 11:45:32 2014 +0200
+++ b/common/util.c	Tue Sep 16 19:45:19 2014 +0200
@@ -16,6 +16,7 @@
 #include <grp.h>
 #include <string.h>
 #else
+#include <winsafer.h>
 #include <windows.h>
 #include <accctrl.h>
 #include <aclapi.h>
@@ -782,3 +783,72 @@
   return retval;
 }
 #endif
+
+#ifdef WIN32
+/** @brief get a restricted access token
+  *
+  * This function uses the Software Restriction API to obtain the
+  * access token for a process run als normal user.
+  *
+  * @returns A restricted handle or NULL on error.
+  */
+HANDLE
+get_restricted_token()
+{
+  SAFER_LEVEL_HANDLE user_level = NULL;
+  HANDLE retval = NULL;
+  SID_IDENTIFIER_AUTHORITY medium_identifier = {SECURITY_MANDATORY_LABEL_AUTHORITY};
+  PSID medium_sid = NULL;
+  TOKEN_MANDATORY_LABEL integrity_label;
+
+  memset (&integrity_label, 0, sizeof (integrity_label));
+
+  if (!SaferCreateLevel(SAFER_SCOPEID_USER,
+                        SAFER_LEVELID_NORMALUSER,
+                        SAFER_LEVEL_OPEN, &user_level, NULL))
+    {
+      PRINTLASTERROR ("Failed to create user level.\n");
+      return NULL;
+    }
+
+  if (!SaferComputeTokenFromLevel(user_level, NULL, &retval, 0, NULL))
+    {
+      SaferCloseLevel(user_level);
+      return NULL;
+    }
+
+  SaferCloseLevel(user_level);
+
+  /* Set the SID to medium it will still be high otherwise. Even if
+  there is no high access allowed. */
+  if (!AllocateAndInitializeSid(&medium_identifier,
+                               1,
+                               SECURITY_MANDATORY_MEDIUM_RID,
+                               0,
+                               0,
+                               0,
+                               0,
+                               0,
+                               0,
+                               0,
+                               &medium_sid))
+    {
+      PRINTLASTERROR ("Failed to initialize sid.\n");
+      return NULL;
+    }
+
+  integrity_label.Label.Attributes = SE_GROUP_INTEGRITY;
+  integrity_label.Label.Sid        = medium_sid;
+
+  if (!SetTokenInformation(retval,
+                           TokenIntegrityLevel,
+                           &integrity_label,
+                           sizeof(TOKEN_MANDATORY_LABEL)))
+    {
+      PRINTLASTERROR ("Failed to set token integrity.\n");
+      return NULL;
+    }
+
+  return retval;
+}
+#endif
--- a/common/util.h	Tue Sep 16 11:45:32 2014 +0200
+++ b/common/util.h	Tue Sep 16 19:45:19 2014 +0200
@@ -150,6 +150,23 @@
   */
 bool has_high_integrity(HANDLE hToken);
 
+/** @brief get a restricted access token to execute nss process
+  *
+  * This function uses the Software Restriction API to obtain the
+  * access token for a process run als normal user.
+  *
+  * @returns A restricted handle or NULL on error.
+  */
+HANDLE get_restricted_token();
+
+/** @brief get a normal user access token
+  *
+  * The trusted acces token is not elevated but has the normal user rights.
+  *
+  * @returns A normal user handle or NULL on error.
+  */
+HANDLE get_normal_token();
+
 #endif
 
 #ifdef __cplusplus
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/packaging/CMakeLists.txt	Tue Sep 16 19:45:19 2014 +0200
@@ -0,0 +1,23 @@
+# Configure packaging script for testing
+configure_file (win-createpackage.sh.in win-createpackage.sh @ONLY)
+configure_file (create-dist-package.sh.in create-dist-package.sh @ONLY)
+configure_file (linux-createpackage.sh.in linux-createpackage.sh @ONLY)
+configure_file (linux-installer.inc.in linux-installer.inc @ONLY)
+configure_file (linux-installer.l10n-de linux-installer.l10n-de COPYONLY)
+
+if (WIN32)
+   # Build the nss safer plugin.
+   include_directories(${CMAKE_SOURCE_DIR}/common)
+
+   add_library(desktopshellrun SHARED desktopshellrun.cpp)
+   target_link_libraries(desktopshellrun
+      trustbridge_common
+      -luserenv
+      -lshell32
+      -lcrypt32
+      -lssp
+      -lshlwapi
+      ${POLARSSL_LIBRARIES}) # trustbridge_common pulls it in.
+   set_target_properties(desktopshellrun PROPERTIES PREFIX "")
+   set_target_properties(desktopshellrun PROPERTIES OUTPUT_NAME "DesktopShellRun")
+endif()
--- a/packaging/create-dist-package.sh.in	Tue Sep 16 11:45:32 2014 +0200
+++ b/packaging/create-dist-package.sh.in	Tue Sep 16 19:45:19 2014 +0200
@@ -58,6 +58,7 @@
 # Create a temporary NSIS file for the uninstaller cration
 LC_ALL="de_DE.latin-1" makensis -Dfiles_dir=$TMPDIR/windows \
     -Dcompany="Bundesamt für Sicherheit in der Informationstechnik" \
+    -Dplugin_dir="@CMAKE_CURRENT_BINARY_DIR@" \
     -Dversion_number=@PROJECT_VERSION@ \
     -Dsetupname="$TMPDIR/TrustBridge-@PROJECT_VERSION@-uni.exe" \
     -Dproductname="TrustBridge" \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/packaging/desktopshellrun.cpp	Tue Sep 16 19:45:19 2014 +0200
@@ -0,0 +1,326 @@
+/* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik
+ * Software engineering by Intevation GmbH
+ *
+ * This file is Free Software under the GNU GPL (v>=2)
+ * and comes with ABSOLUTELY NO WARRANTY!
+ * See LICENSE.txt for details.
+ */
+
+/**
+ * @file tasksched_run_as.cpp
+ * @brief Run a command with the Task Scheduler API
+ *
+ * This effectively starts a program as the user regardles of the current
+ * process token.
+ */
+#include <windows.h>
+#include "logging.h"
+#include "strhelp.h"
+
+#ifndef INITGUID
+#define INITGUID
+#endif
+
+#include <initguid.h>
+#include <mstask.h>
+#include <wchar.h>
+#include <ole2.h>
+#include <shldisp.h>
+#include <shobjidl.h>
+#include <exdisp.h>
+#include <shlguid.h>
+
+/* Some declarations missing in mingw-w64 3.1.0 taken from msdn */
+
+__CRT_UUID_DECL(IShellWindows, 0x85CB6900, 0x4D95, 0x11CF,
+                0x96, 0x0C, 0x00, 0x80, 0xC7, 0xF4, 0xEE, 0x85);
+
+DEFINE_GUID(IID_IShellWindows,
+            0x85CB6900, 0x4D95, 0x11CF,
+            0x96, 0x0C, 0x00, 0x80, 0xC7, 0xF4, 0xEE, 0x85);
+DEFINE_GUID(CLSID_ShellWindows,
+            0x9BA05972, 0xF6A8, 0x11CF,
+            0xA4, 0x42, 0x00, 0xA0, 0xC9, 0x0A, 0x8F, 0x39);
+
+
+__CRT_UUID_DECL(IShellDispatch2, 0xA4C6892C, 0x3BA9, 0x11d2,
+                0x9D, 0xEA, 0x00, 0xC0, 0x4F, 0xB1, 0x61, 0x62);
+__CRT_UUID_DECL(IShellFolderViewDual,  0xe7a1af80, 0x4d96,
+                0x11cf, 0x96, 0x0c, 0x00, 0x80, 0xc7, 0xf4, 0xee, 0x85);
+
+#ifndef SWC_DESKTOP /* Will probably be addedd in future mingw */
+#define SWC_DESKTOP 0x00000008
+/* from http://msdn.microsoft.com/en-us/library/windows/desktop/cc836581%28v=vs.85%29.aspx */
+#endif
+
+#undef INITGUID
+
+#ifdef DO_RELEASE_BUILD
+bool g_debug = false;
+#else
+bool g_debug = true;
+#endif
+
+typedef struct _stack_t
+{
+  struct _stack_t *next;
+  char text[1];          /* This should be the length of string_size. */
+} stack_t;
+
+static HINSTANCE g_hInstance; /* Our Instance. */
+
+#define UNUSED(x) (void)(x)
+
+/** @brief the actual execuation call on the shell dispatcher
+ *
+ * @param[in] disp The shell dispatcher to use for shell execute.
+ * @param[in] fName The file that should be exectued.
+ *
+ * @returns true on success.
+ */
+static bool
+shellexecute(IShellDispatch2 *disp, wchar_t *fName)
+{
+  BSTR bName = NULL,
+       bParam = NULL,
+       bDir = NULL,
+       bOp = NULL;
+  VARIANT vParams[4];
+  HRESULT hr;
+
+  if (!fName || !disp)
+    {
+      ERRORPRINTF ("Invalid call to shellexecute.");
+      return false;
+    }
+
+  bName = SysAllocString(fName);
+  bParam = SysAllocString(L"");
+  bDir = SysAllocString(L"");
+  bOp = SysAllocString(L"");
+
+  if (!bName || !bParam || !bDir || !bOp)
+    {
+      /* Out of memory */
+      ERRORPRINTF ("Failed to allocate bstr values ");
+      return false;
+    }
+
+  vParams[0].vt = VT_BSTR;
+  vParams[0].bstrVal = bParam;
+  vParams[1].vt = VT_BSTR;
+  vParams[1].bstrVal = bDir;
+  vParams[2].vt = VT_BSTR;
+  vParams[2].bstrVal = bOp;
+  vParams[3].vt = VT_INT;
+  vParams[3].intVal = SW_SHOWNORMAL;
+
+  hr = disp->ShellExecute(bName, vParams[0], vParams[1], vParams[2], vParams[3]);
+
+  SysFreeString(bName);
+  SysFreeString(bParam);
+  SysFreeString(bOp);
+  SysFreeString(bDir);
+
+  if (FAILED(hr))
+    {
+      ERRORPRINTF ("Failed to execute.");
+      return false;
+    }
+  return true;
+}
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Standard entry point for DLLs. */
+int WINAPI
+DllMain (HANDLE hinst, DWORD reason, LPVOID reserved)
+{
+  UNUSED(reserved);
+  if (reason == DLL_PROCESS_ATTACH)
+    g_hInstance = (HINSTANCE)hinst;
+  return TRUE;
+}
+
+/** @brief Execute a command with the current running shell.
+ *
+ * This function is intended to be called when you want to
+ * make sure that your application is not executed with higher
+ * privileges then the normal desktop session.
+ *
+ * The code is based on the idea:
+ * http://blogs.msdn.com/b/oldnewthing/archive/2013/11/18/10468726.aspx
+ *
+ * The function signature is explained by NSIS.
+ */
+void __declspec(dllexport) __cdecl Exec(HWND hwndParent,
+                                        int string_size,
+                                        char *variables,
+                                        stack_t **stacktop)
+{
+  UNUSED(hwndParent);
+  UNUSED(string_size);
+  HRESULT hr;
+  wchar_t *wbuf = NULL;
+  IShellWindows *shellWindows = NULL;
+  IShellBrowser *shellBrowser = NULL;
+  IShellView *shellView = NULL;
+  IShellFolderViewDual *folderView = NULL;
+  IShellDispatch2 *shellDispatch = NULL;
+  IServiceProvider *serviceProv = NULL;
+  HWND hwnd;
+  IDispatch *disp = NULL,
+             *bgDisp = NULL,
+              *sDisp = NULL;
+  VARIANT vEmpty = {};
+
+
+  if (!stacktop || !*stacktop || !(*stacktop)->text)
+    {
+      ERRORPRINTF ("Invalid call to exec :");
+      return;
+    }
+
+  /* Initialize com ctx */
+  hr = CoInitialize(NULL);
+  if(FAILED(hr))
+    {
+      ERRORPRINTF ("CoInitializeEx failed. error = 0x%lx.", hr);
+      return;
+    }
+
+  /* Get the shell interface */
+  hr = CoCreateInstance(CLSID_ShellWindows,
+                        NULL, CLSCTX_LOCAL_SERVER,
+                        IID_PPV_ARGS(&shellWindows));
+  if (FAILED(hr))
+    {
+      ERRORPRINTF ("Failed to get shell interface.");
+      goto done;
+    }
+
+  /* Get the desktop shell window */
+  hr = shellWindows->FindWindowSW(&vEmpty,
+                                  &vEmpty,
+                                  SWC_DESKTOP,
+                                  (long*)&hwnd,
+                                  SWFO_NEEDDISPATCH,
+                                  &disp);
+  if (FAILED(hr))
+    {
+      ERRORPRINTF ("Failed to find the desktop dispatcher.");
+      goto done;
+    }
+
+  hr = disp->QueryInterface(IID_PPV_ARGS(&serviceProv));
+
+  if (FAILED(hr))
+    {
+      ERRORPRINTF ("Failed to get the service provider.");
+      goto done;
+    }
+
+  /* Get the shell browser */
+  hr = serviceProv->QueryService(SID_STopLevelBrowser, IID_PPV_ARGS(&shellBrowser));
+  if (FAILED(hr))
+    {
+      ERRORPRINTF ("Failed to find the top level browser.");
+      goto done;
+    }
+
+  hr = shellBrowser->QueryActiveShellView(&shellView);
+
+  if (FAILED(hr))
+    {
+      ERRORPRINTF ("Failed to find the active view.");
+      goto done;
+    }
+
+  hr = shellView->GetItemObject(SVGIO_BACKGROUND, IID_PPV_ARGS(&bgDisp));
+
+  if (FAILED(hr))
+    {
+      ERRORPRINTF ("Failed to get the views background.");
+      goto done;
+    }
+
+  hr = bgDisp->QueryInterface(IID_PPV_ARGS(&folderView));
+
+  if (FAILED(hr))
+    {
+      ERRORPRINTF ("Failed to get the folder view.");
+      goto done;
+    }
+
+
+  hr = folderView->get_Application(&sDisp);
+
+  if (FAILED(hr))
+    {
+      ERRORPRINTF ("Failed to get the shell dispatch.");
+      goto done;
+    }
+
+  hr = sDisp->QueryInterface(IID_PPV_ARGS(&shellDispatch));
+
+  if (FAILED(hr))
+    {
+      ERRORPRINTF ("Failed to get the shell dispatch interface.");
+      goto done;
+    }
+
+  wbuf = utf8_to_wchar((*stacktop)->text, strlen((*stacktop)->text));
+  if (!wbuf)
+    {
+      ERRORPRINTF ("Failed to convert argument to wchar. error = 0x%lx.", hr);
+      goto done;
+    }
+
+  if (!shellexecute(shellDispatch, wbuf))
+    {
+      ERRORPRINTF ("Failed to execute.");
+    }
+  xfree (wbuf);
+done:
+  if (folderView)
+    {
+      folderView->Release();
+    }
+  if (disp)
+    {
+      disp->Release();
+    }
+  if (shellBrowser)
+    {
+      shellBrowser->Release();
+    }
+  if (shellWindows)
+    {
+      shellWindows->Release();
+    }
+  if (shellView)
+    {
+      shellView->Release();
+    }
+  if (sDisp)
+    {
+      sDisp->Release();
+    }
+  if (shellDispatch)
+    {
+      shellDispatch->Release();
+    }
+  if (serviceProv)
+    {
+      serviceProv->Release();
+    }
+  CoUninitialize();
+  return;
+}
+#ifdef __cplusplus
+}
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/packaging/exdll.h	Tue Sep 16 19:45:19 2014 +0200
@@ -0,0 +1,39 @@
+/* exdll.h for use with TrustBrdige
+ * Copyright (C) 1999-2005 Nullsoft, Inc.
+ * 
+ * This license applies to everything in the NSIS package, except
+ * where otherwise noted.
+ * 
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any
+ * damages arising from the use of this software.
+ * 
+ * Permission is granted to anyone to use this software for any
+ * purpose, including commercial applications, and to alter it and
+ * redistribute it freely, subject to the following restrictions:
+ * 
+ * 1. The origin of this software must not be misrepresented; you must
+ *    not claim that you wrote the original software. If you use this
+ *    software in a product, an acknowledgment in the product
+ *    documentation would be appreciated but is not required.
+ * 
+ * 2. Altered source versions must be plainly marked as such, and must
+ *    not be misrepresented as being the original software.
+ * 
+ * 3. This notice may not be removed or altered from any source
+ *    distribution.
+ ************************************************************
+ * 2005-11-14 wk  Applied license text to orginal exdll.h file from
+ *                NSIS 2.0.4 and did some formatting changes.
+ * 2014-09-16 ah  Stripped out uneccesary stuff for TrustBridge plugin
+ */
+
+#ifndef _EXDLL_H_
+#define _EXDLL_H_
+
+/* only include this file from one place in your DLL.  (it is all
+   static, if you use it in two places it will fail) */
+
+/* For page showing plug-ins */
+
+#endif//_EXDLL_H_
--- a/packaging/trustbridge.nsi	Tue Sep 16 11:45:32 2014 +0200
+++ b/packaging/trustbridge.nsi	Tue Sep 16 19:45:19 2014 +0200
@@ -27,6 +27,8 @@
 !define MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_VALUENAME ""
 !define MULTIUSER_INSTALLMODE_INSTDIR "${productname_short}"
 
+!addplugindir "${plugin_dir}"
+
 !include "MultiUser.nsh"
 !include "MUI2.nsh"
 !include "FileFunc.nsh"
@@ -93,9 +95,9 @@
 Computer installliert. $\r$\n$\r$\n\
 Klicken Sie auf 'Fertig stellen', um den Installations-Assistenten\
 zu schließen."
-;!define MUI_FINISHPAGE_RUN $INSTDIR\trustbridge.exe
-;!define MUI_FINISHPAGE_RUN_TEXT "Anwendung starten"
-;!define MUI_FINISHPAGE_RUN_FUNCTION RunAsUser
+!define MUI_FINISHPAGE_RUN $INSTDIR\trustbridge.exe
+!define MUI_FINISHPAGE_RUN_TEXT "Anwendung starten"
+!define MUI_FINISHPAGE_RUN_FUNCTION RunAsUser
 !define MUI_FINISHPAGE_LINK "Mehr unter ${info_url}"
 !define MUI_FINISHPAGE_LINK_LOCATION "${info_url}"
 
@@ -186,7 +188,7 @@
 ; the UI elevated as this could be a security
 ; problem.
 Function RunAsUser
-  ExecShell "" "$INSTDIR\trustbridge.exe"
+  DesktopShellRun::Exec "$INSTDIR\trustbridge.exe"
 FunctionEnd
 
 ;--------------------------------
@@ -258,6 +260,9 @@
 
   !insertmacro MUI_STARTMENU_WRITE_END
 done:
+  StrCmp $is_update '1' run_silent dont_run
+run_silent:
+dont_run:
 
 SectionEnd
 
--- a/packaging/win-createpackage.sh.in	Tue Sep 16 11:45:32 2014 +0200
+++ b/packaging/win-createpackage.sh.in	Tue Sep 16 19:45:19 2014 +0200
@@ -26,6 +26,7 @@
 
 makensis -Dfiles_dir=$TMPDIR \
     -Dcompany="Bundesamt für Sicherheit in der Informationstechnik" \
+    -Dplugin_dir="@CMAKE_CURRENT_BINARY_DIR@" \
     -Dversion_number=@PROJECT_VERSION@ \
     -Dsetupname="$TMPINST" \
     -Dproductname="TrustBridge" \
@@ -42,6 +43,7 @@
 
 makensis -Dfiles_dir=$TMPDIR \
     -Dcompany="Bundesamt für Sicherheit in der Informationstechnik" \
+    -Dplugin_dir="@CMAKE_CURRENT_BINARY_DIR@" \
     -Dversion_number=@PROJECT_VERSION@ \
     -Dsetupname="@CMAKE_BINARY_DIR@/TrustBridge-@PROJECT_VERSION@.exe" \
     -Dproductname="TrustBridge" \

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