[PATCH] (issue66) Implement is_system_install and use it
Wald Commits
scm-commit at wald.intevation.org
Tue Jul 29 18:13:02 CEST 2014
# HG changeset patch
# User Andre Heinecke <andre.heinecke at intevation.de>
# Date 1406650377 -7200
# Node ID 216a65d7fc4b8c44bf78cd208234998a16a7cd4f
# Parent c9a31544aaab78d7374a3e6179757322480d2e33
(issue66) Implement is_system_install and use it
This has completly different implementations for linux
and Windows. The commit also moves some code into util.c
for better reuse.
diff -r c9a31544aaab -r 216a65d7fc4b cinst/nssstore_linux.c
--- a/cinst/nssstore_linux.c Tue Jul 29 13:15:32 2014 +0200
+++ b/cinst/nssstore_linux.c Tue Jul 29 18:12:57 2014 +0200
@@ -25,52 +25,10 @@
#include "nssstore.h"
#include "logging.h"
#include "strhelp.h"
+#include "util.h"
#define NSS_PROCESS_NAME "mozilla"
-/**@brief get the current path of the executable
- *
- * Looks up the current executables directory. The caller
- * has to free the return value.
- *
- * The returned value includes the last /
- *
- * @returns the absolute directory of the currently executed executable or NULL
- */
-char *
-get_exe_dir()
-{
- char *retval = NULL,
- *p = NULL,
- buf[PATH_MAX];
- ssize_t ret;
- size_t path_len = 0;
-
- ret = readlink ("/proc/self/exe", buf, PATH_MAX);
- if (ret <= 0)
- {
- ERRORPRINTF ("readlink failed\n");
- return NULL;
- }
-
- buf[ret] = '\0';
-
- /* cut off the filename */
- p = strrchr (buf, '/');
- if (p == NULL)
- {
- ERRORPRINTF ("No filename found.\n");
- return NULL;
- }
- *(p + 1) = '\0';
-
- path_len = strlen (buf);
- retval = xmalloc (path_len + 1);
- strncpy (retval, buf, path_len);
- retval[path_len] = '\0';
-
- return retval;
-}
/**@brief Start the process to install / remove
*
@@ -123,7 +81,7 @@
}
/* Set up the file name of the installer process */
- inst_dir = get_exe_dir();
+ inst_dir = get_install_dir();
if (inst_dir == NULL)
{
ERRORPRINTF ("Failed to find installation directory.\n");
diff -r c9a31544aaab -r 216a65d7fc4b cinst/nssstore_win.c
--- a/cinst/nssstore_win.c Tue Jul 29 13:15:32 2014 +0200
+++ b/cinst/nssstore_win.c Tue Jul 29 18:12:57 2014 +0200
@@ -171,114 +171,6 @@
}
return true;
}
-
-/**@brief Read (and expand if necessary) a registry string.
- *
- * Reads a registry string and calls ExpandEnvironmentString
- * if necessary on it. Returns a newly allocated string array
- * with the expanded registry value converted to UTF-8
- *
- * Caller has to free return value with free.
- *
- * @param [in] root the root key (e.g. HKEY_LOCAL_MACHINE)
- * @param [in] key the key
- * @param [in] name the name of the value to read.
- *
- * @returns the expanded, null terminated utf-8 string of the value.
- * or NULL on error.
- */
-static char*
-read_registry_string (const HKEY root, const wchar_t *key,
- const wchar_t *name)
-{
- HKEY key_handle = NULL;
- DWORD size = 0,
- type = 0,
- ex_size = 0,
- dwRet = 0;
- LONG ret = 0;
- char *retval = NULL;
- wchar_t *buf = NULL,
- *ex_buf = NULL;
- if (root == NULL || key == NULL || name == NULL)
- {
- ERRORPRINTF ("Invalid call to read_registry_string");
- return NULL;
- }
-
- ret = RegOpenKeyExW (root, key, 0, KEY_READ, &key_handle);
- if (ret != ERROR_SUCCESS)
- {
- ERRORPRINTF ("Failed to open key.");
- return NULL;
- }
-
- /* Get the size */
- ret = RegQueryValueExW (key_handle, name, 0, NULL, NULL, &size);
- if (ret != ERROR_MORE_DATA && !(ret == ERROR_SUCCESS && size != 0))
- {
- ERRORPRINTF ("Failed to get required registry size.");
- return retval;
- }
-
- /* Size is size in bytes not in characters */
- buf = xmalloc (size + sizeof(wchar_t));
-
- /* If the stored value is not zero terminated the returned value also
- is not zero terminated. That's why we reserve more and ensure it's
- initialized. */
- memset (buf, 0, size + sizeof(wchar_t));
-
- ret = RegQueryValueExW (key_handle, name, 0, &type, (LPBYTE) buf, &size);
- if (ret != ERROR_SUCCESS)
- {
- ERRORPRINTF ("Failed get registry value.");
- return retval;
- }
-
- if (type == REG_SZ || (type == REG_EXPAND_SZ && wcschr (buf, '%') == NULL))
- {
- /* Nothing to expand, we are done */
- retval = wchar_to_utf8 (buf, wcslen (buf));
- goto done;
- }
-
- if (type != REG_EXPAND_SZ)
- {
- ERRORPRINTF ("Unhandled registry type %i", type);
- goto done;
- }
-
- /* Expand the registry string */
- ex_size = ExpandEnvironmentStringsW (buf, NULL, 0);
-
- if (ex_size == 0)
- {
- PRINTLASTERROR ("Failed to determine expanded environment size.");
- goto done;
- }
-
- ex_buf = xmalloc ((ex_size + 1) * sizeof(wchar_t));
-
- dwRet = ExpandEnvironmentStringsW (buf, ex_buf, ex_size);
-
- ex_buf[ex_size] = '\0'; /* Make sure it's a string */
-
- if (dwRet == 0 || dwRet != ex_size)
- {
- PRINTLASTERROR ("Failed to expand environment variables.");
- goto done;
- }
-
- retval = wchar_to_utf8 (ex_buf, ex_size);
-
-done:
- xfree (ex_buf);
- xfree (buf);
-
- RegCloseKey (key_handle);
- return retval;
-}
/**@brief Get the path to all users default registry hive
*
* Enumerates the keys in #PROFILE_LIST and retuns a
diff -r c9a31544aaab -r 216a65d7fc4b common/util.c
--- a/common/util.c Tue Jul 29 13:15:32 2014 +0200
+++ b/common/util.c Tue Jul 29 18:12:57 2014 +0200
@@ -19,8 +19,181 @@
#include <windows.h>
#endif
+#ifndef APPNAME
+#define APPNAME "TrustBridge"
+#endif
+
#ifdef WIN32
-char * get_install_dir()
+char*
+read_registry_string (const HKEY root, const wchar_t *key,
+ const wchar_t *name)
+{
+ HKEY key_handle = NULL;
+ DWORD size = 0,
+ type = 0,
+ ex_size = 0,
+ dwRet = 0;
+ LONG ret = 0;
+ char *retval = NULL;
+ wchar_t *buf = NULL,
+ *ex_buf = NULL;
+ if (root == NULL || key == NULL || name == NULL)
+ {
+ ERRORPRINTF ("Invalid call to read_registry_string");
+ return NULL;
+ }
+
+ ret = RegOpenKeyExW (root, key, 0, KEY_READ, &key_handle);
+ if (ret != ERROR_SUCCESS)
+ {
+ ERRORPRINTF ("Failed to open key.");
+ return NULL;
+ }
+
+ /* Get the size */
+ ret = RegQueryValueExW (key_handle, name, 0, NULL, NULL, &size);
+ if (ret != ERROR_MORE_DATA && !(ret == ERROR_SUCCESS && size != 0))
+ {
+ ERRORPRINTF ("Failed to get required registry size.");
+ return retval;
+ }
+
+ /* Size is size in bytes not in characters */
+ buf = xmalloc (size + sizeof(wchar_t));
+
+ /* If the stored value is not zero terminated the returned value also
+ is not zero terminated. That's why we reserve more and ensure it's
+ initialized. */
+ memset (buf, 0, size + sizeof(wchar_t));
+
+ ret = RegQueryValueExW (key_handle, name, 0, &type, (LPBYTE) buf, &size);
+ if (ret != ERROR_SUCCESS)
+ {
+ ERRORPRINTF ("Failed get registry value.");
+ return retval;
+ }
+
+ if (type == REG_SZ || (type == REG_EXPAND_SZ && wcschr (buf, '%') == NULL))
+ {
+ /* Nothing to expand, we are done */
+ retval = wchar_to_utf8 (buf, wcslen (buf));
+ goto done;
+ }
+
+ if (type != REG_EXPAND_SZ)
+ {
+ ERRORPRINTF ("Unhandled registry type %i", type);
+ goto done;
+ }
+
+ /* Expand the registry string */
+ ex_size = ExpandEnvironmentStringsW (buf, NULL, 0);
+
+ if (ex_size == 0)
+ {
+ PRINTLASTERROR ("Failed to determine expanded environment size.");
+ goto done;
+ }
+
+ ex_buf = xmalloc ((ex_size + 1) * sizeof(wchar_t));
+
+ dwRet = ExpandEnvironmentStringsW (buf, ex_buf, ex_size);
+
+ ex_buf[ex_size] = '\0'; /* Make sure it's a string */
+
+ if (dwRet == 0 || dwRet != ex_size)
+ {
+ PRINTLASTERROR ("Failed to expand environment variables.");
+ goto done;
+ }
+
+ retval = wchar_to_utf8 (ex_buf, ex_size);
+
+done:
+ xfree (ex_buf);
+ xfree (buf);
+
+ RegCloseKey (key_handle);
+ return retval;
+}
+
+
+/** @brief Compare two paths for equality based on the filename.
+ *
+ * Expand the paths by using GetFullPathName and do a string
+ * comparison on the result to check for equality.
+ *
+ * To be sure if it is really the same file it would be better
+ * to open the files and compare the serial number but this
+ * suffices for checks that only impact on the options presented
+ * to the user (try a system wide installation or not)
+ *
+ * If one file does not exist the function returns false. If
+ * The path is longer then MAX_PATH this function also returns
+ * false.
+ *
+ * @param [in] path1 first path to compare
+ * @paran [in] path2 first path to compare
+ * @returns true if the paths are the same.
+ */
+bool
+paths_equal (const char *path1, const char *path2)
+{
+ bool ret = false;
+ wchar_t buf1[MAX_PATH],
+ buf2[MAX_PATH];
+ wchar_t *wpath1 = NULL,
+ *wpath2 = NULL;
+ DWORD retval = 0;
+
+ if (!path1 || !path2)
+ {
+ return false;
+ }
+
+ wpath1 = utf8_to_wchar(path1, strnlen(path1, MAX_PATH));
+ wpath2 = utf8_to_wchar(path2, strnlen(path2, MAX_PATH));
+
+ if (wpath1 == NULL || wpath2 == NULL)
+ {
+ ERRORPRINTF ("Failed to convert paths to wchar.");
+ goto done;
+ }
+
+ retval = GetFullPathNameW (wpath1, MAX_PATH, buf1, NULL);
+ if (retval >= MAX_PATH || retval != wcsnlen (buf1, MAX_PATH))
+ {
+ ERRORPRINTF ("Path1 too long.");
+ goto done;
+ }
+ if (retval == 0)
+ {
+ PRINTLASTERROR ("Failed to get Full Path name.");
+ goto done;
+ }
+
+ retval = GetFullPathNameW (wpath2, MAX_PATH, buf2, NULL);
+ if (retval >= MAX_PATH || retval != wcsnlen (buf2, MAX_PATH))
+ {
+ ERRORPRINTF ("Path2 too long.");
+ goto done;
+ }
+ if (retval == 0)
+ {
+ PRINTLASTERROR ("Failed to get Full Path name.");
+ goto done;
+ }
+
+ ret = wcscmp (buf1, buf2) == 0;
+done:
+ xfree (wpath1);
+ xfree (wpath2);
+
+ return ret;
+}
+
+char *
+get_install_dir()
{
wchar_t wPath[MAX_PATH];
char *utf8path = NULL;
@@ -68,7 +241,6 @@
return to;
}
-
PSID
get_process_owner(HANDLE hProcess)
{
@@ -102,6 +274,132 @@
}
return NULL;
}
+
+bool
+is_system_install()
+{
+ char *reg_inst_dir = NULL,
+ *real_prefix = NULL;
+ bool ret = false;
+
+ reg_inst_dir = read_registry_string (HKEY_LOCAL_MACHINE,
+ L"Software\\"APPNAME, L"");
+
+ if (reg_inst_dir == NULL)
+ {
+ return false;
+ }
+ DEBUGPRINTF ("Registered installation directory: %s\n", reg_inst_dir);
+
+ real_prefix = get_install_dir();
+
+ if (!real_prefix)
+ {
+ DEBUGPRINTF ("Failed to obtain installation prefix.");
+ xfree (reg_inst_dir);
+ return false;
+ }
+
+ ret = paths_equal (real_prefix, reg_inst_dir);
+
+ xfree (real_prefix);
+ xfree (reg_inst_dir);
+ DEBUGPRINTF ("Is system install? %s\n", ret ? "true" : "false");
+ return ret;
+}
+#else /* WIN32 */
+
+char *
+get_install_dir()
+{
+ char *retval = NULL,
+ *p = NULL,
+ buf[MAX_PATH_LINUX];
+ ssize_t ret;
+ size_t path_len = 0;
+
+ ret = readlink ("/proc/self/exe", buf, MAX_PATH_LINUX);
+ if (ret <= 0)
+ {
+ ERRORPRINTF ("readlink failed\n");
+ return NULL;
+ }
+
+ buf[ret] = '\0';
+
+ /* cut off the filename */
+ p = strrchr (buf, '/');
+ if (p == NULL)
+ {
+ ERRORPRINTF ("No filename found.\n");
+ return NULL;
+ }
+ *(p + 1) = '\0';
+
+ path_len = strlen (buf);
+ retval = xmalloc (path_len + 1);
+ strncpy (retval, buf, path_len);
+ retval[path_len] = '\0';
+
+ return retval;
+}
+
+bool
+is_system_install()
+{
+ FILE *system_config;
+ int read_lines = 0;
+ char linebuf[MAX_PATH_LINUX + 7],
+ * inst_dir = NULL;
+ bool retval = false;
+ size_t inst_dir_len = 0;
+
+ system_config = fopen ("/etc/"APPNAME"/"APPNAME"-inst.cfg", "r");
+ if (system_config == NULL)
+ {
+ DEBUGPRINTF ("No system wide install configuration found.\n");
+ return false;
+ }
+ inst_dir = get_install_dir ();
+
+ if (inst_dir == NULL)
+ {
+ ERRORPRINTF ("Failed to find installation directory.\n");
+ fclose(system_config);
+ return false;
+ }
+
+ inst_dir_len = strnlen (inst_dir, MAX_PATH_LINUX);
+
+ if (inst_dir_len == 0 || inst_dir_len >= MAX_PATH_LINUX)
+ {
+ ERRORPRINTF ("Installation directory invalid.\n");
+ fclose(system_config);
+ return false;
+ }
+
+ /* Read the first 10 lines and look for PREFIX. if it is not found
+ we return false. */
+ while (read_lines < 10 && fgets (linebuf, MAX_PATH_LINUX + 7,
+ system_config) != NULL)
+ {
+ if (str_starts_with (linebuf, "PREFIX="))
+ {
+ /* The last character is always a linebreak in a valid system_config
+ file so we can strip it. If this is not true the file is invalid.
+ linebuf is > 7 atm otherwise prefix= would not have been matched. */
+ linebuf[strlen(linebuf) - 1] = '\0';
+ retval = str_starts_with (inst_dir, linebuf + 7);
+ break;
+ }
+ read_lines++;
+ }
+
+ fclose (system_config);
+ xfree (inst_dir);
+ DEBUGPRINTF ("Is system install? %s\n", retval ? "true" : "false");
+ return retval;
+}
#endif
bool
@@ -128,7 +426,8 @@
return ret;
}
-bool is_admin()
+bool
+is_admin()
{
#ifndef _WIN32
struct passwd *current_user = getpwuid (geteuid());
diff -r c9a31544aaab -r 216a65d7fc4b common/util.h
--- a/common/util.h Tue Jul 29 13:15:32 2014 +0200
+++ b/common/util.h Tue Jul 29 18:12:57 2014 +0200
@@ -21,6 +21,11 @@
extern "C" {
#endif
+#ifndef WIN32
+/**@def Some value to use as equivalent as MAX_PATH on windows */
+#define MAX_PATH_LINUX 4000
+#endif
+
/**@brief Check if the current process is running with elevated privileges.
*
* Elevates the current process token to check if it is marked as elevated.
@@ -29,6 +34,20 @@
* @returns true if the current process is elevated.*/
bool is_elevated();
+/**@brief Check if the Software is installed system wide
+ *
+ * On Windows this checks if a registry key under HKLM exists for
+ * trustbridge and that the installation path mentioned there matches
+ * the current module path.
+ *
+ * On linux this looks for the installation configuration in /etc
+ * and checks if the current process is inside the installation prefix.
+ *
+ * The checked path is limited to MAX_PATH on Windows and @MAX_PATH_LINUX on
+ * Linux.
+ */
+bool is_system_install();
+
/**@brief Check if the user is in the administrators group.
*
* The function checks if the account that startet this process
@@ -38,6 +57,18 @@
*/
bool is_admin();
+/**@brief Get the directory in which the current process resides in
+ *
+ * Look up the directory in which the current process is placed.
+ * If the path is longer then MAX_PATH NULL is returned.
+ *
+ * Returns a utf-8 encoded string that has to be freed by the caller
+ * on linux the path is returned as is including the last /.
+ *
+ * @returns The directory of the current process
+ */
+char * get_install_dir();
+
#ifdef WIN32
/**@brief Get a copy of the processes owner sid
*
@@ -52,16 +83,23 @@
*/
PSID get_process_owner(HANDLE hProcess);
-/**@brief Get the directory in which the current process resides in
+/**@brief Read (and expand if necessary) a registry string.
*
- * Look up the directory in which the current process is placed.
- * If the path is longer then MAX_PATH NULL is returned.
+ * Reads a registry string and calls ExpandEnvironmentString
+ * if necessary on it. Returns a newly allocated string array
+ * with the expanded registry value converted to UTF-8
*
- * Returns a utf-8 encoded string that has to be freed by the caller
+ * Caller has to free return value with free.
*
- * @returns The directory of the current process
+ * @param [in] root the root key (e.g. HKEY_LOCAL_MACHINE)
+ * @param [in] key the key
+ * @param [in] name the name of the value to read.
+ *
+ * @returns the expanded, null terminated utf-8 string of the value.
+ * or NULL on error.
*/
-char * get_install_dir();
+char * read_registry_string (const HKEY root, const wchar_t *key,
+ const wchar_t *name);
#endif
#ifdef __cplusplus
diff -r c9a31544aaab -r 216a65d7fc4b ui/installwrapper.cpp
--- a/ui/installwrapper.cpp Tue Jul 29 13:15:32 2014 +0200
+++ b/ui/installwrapper.cpp Tue Jul 29 18:12:57 2014 +0200
@@ -96,7 +96,7 @@
shExecInfo.cbSize = sizeof(SHELLEXECUTEINFOW);
shExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
- if (!is_admin()) {
+ if (!is_admin() || !is_system_install()) {
shExecInfo.lpVerb = L"open";
} else {
shExecInfo.lpVerb = L"runas";
@@ -156,7 +156,7 @@
parameters << "list=" + mCertListFile << "choices=" + choicesFile.fileName();
bool sudo_started = false;
- bool use_sudo = is_admin();
+ bool use_sudo = is_admin() && is_system_install();
if (use_sudo) {
QStringList sudoPrograms;
sudoPrograms << "gksudo" << "kdesudo" << "sudo";
diff -r c9a31544aaab -r 216a65d7fc4b ui/mainwindow.cpp
--- a/ui/mainwindow.cpp Tue Jul 29 13:15:32 2014 +0200
+++ b/ui/mainwindow.cpp Tue Jul 29 18:12:57 2014 +0200
@@ -277,7 +277,7 @@
// shExecInfo.fMask = SEE_MASK_NOASYNC;
shExecInfo.nShow = SW_SHOWDEFAULT;
- if (!is_admin()) {
+ if (!is_system_install() || !is_admin()) {
shExecInfo.lpVerb = L"open";
} else {
shExecInfo.lpVerb = L"runas";
@@ -299,7 +299,7 @@
QStringList parameters;
parameters << "--prefix" << installDir.path();
bool sudo_started = false;
- bool use_sudo = is_admin();
+ bool use_sudo = is_admin() && is_system_install();
if (use_sudo) {
QStringList sudoPrograms;
sudoPrograms << "gksudo" << "kdesudo" << "sudo";
@@ -566,7 +566,7 @@
mInstallButton = new QPushButton(" " + tr("Install certificates again"));
mInstallButton->setFixedHeight(30);
#ifdef Q_OS_WIN
- if (is_admin()) {
+ if (is_admin() && is_system_install()) {
QIcon uacShield = QApplication::style()->standardIcon(QStyle::SP_VistaShield);
mInstallButton->setIcon(uacShield);
}
More information about the Trustbridge-commits
mailing list