-doxygen
[oweals/gnunet.git] / src / util / os_installation.c
index b63a19d2e9d6c9ffcf86fd27997ccd57de890229..30e729dc63b36360daec7297501bd85aa664346e 100644 (file)
@@ -4,7 +4,7 @@
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 2, or (at your
+     by the Free Software Foundation; either version 3, or (at your
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
 #include <unistr.h> /* for u16_to_u8 */
 
 #include "platform.h"
 #include <unistr.h> /* for u16_to_u8 */
 
 #include "platform.h"
-#include "gnunet_common.h"
-#include "gnunet_configuration_lib.h"
-#include "gnunet_disk_lib.h"
-#include "gnunet_os_lib.h"
-#include "gnunet_strings_lib.h"
+#include "gnunet_util_lib.h"
 #if DARWIN
 #include <mach-o/ldsyms.h>
 #include <mach-o/dyld.h>
 #if DARWIN
 #include <mach-o/ldsyms.h>
 #include <mach-o/dyld.h>
@@ -47,6 +43,7 @@
 
 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
 
 
 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
 
+
 #if LINUX
 /**
  * Try to determine path by reading /proc/PID/exe
 #if LINUX
 /**
  * Try to determine path by reading /proc/PID/exe
@@ -119,12 +116,13 @@ get_path_from_proc_exe ()
 }
 #endif
 
 }
 #endif
 
-#if WINDOWS
 
 
+#if WINDOWS
 static HINSTANCE dll_instance;
 
 
 static HINSTANCE dll_instance;
 
 
-/* GNUNET_util_cl_init() in common_logging.c is preferred.
+/**
+ * GNUNET_util_cl_init() in common_logging.c is preferred.
  * This function is only for thread-local storage (not used in GNUnet)
  * and hInstance saving.
  */
  * This function is only for thread-local storage (not used in GNUnet)
  * and hInstance saving.
  */
@@ -230,6 +228,7 @@ get_path_from_module_filename ()
 }
 #endif
 
 }
 #endif
 
+
 #if DARWIN
 /**
  * Signature of the '_NSGetExecutablePath" function.
 #if DARWIN
 /**
  * Signature of the '_NSGetExecutablePath" function.
@@ -295,7 +294,7 @@ get_path_from_dyld_image ()
   c = _dyld_image_count ();
   for (i = 0; i < c; i++)
   {
   c = _dyld_image_count ();
   for (i = 0; i < c; i++)
   {
-    if (_dyld_get_image_header (i) != &_mh_dylib_header)
+    if (((const void *) _dyld_get_image_header (i)) != (const void *)&_mh_dylib_header)
       continue;
     path = _dyld_get_image_name (i);
     if ( (NULL == path) || (0 == strlen (path)) )
       continue;
     path = _dyld_get_image_name (i);
     if ( (NULL == path) || (0 == strlen (path)) )
@@ -419,8 +418,7 @@ os_get_gnunet_path ()
     return ret;
   /* other attempts here */
   LOG (GNUNET_ERROR_TYPE_ERROR,
     return ret;
   /* other attempts here */
   LOG (GNUNET_ERROR_TYPE_ERROR,
-       _
-       ("Could not determine installation path for %s.  Set `%s' environment variable.\n"),
+       _("Could not determine installation path for %s.  Set `%s' environment variable.\n"),
        "GNUnet", "GNUNET_PREFIX");
   return NULL;
 }
        "GNUnet", "GNUNET_PREFIX");
   return NULL;
 }
@@ -456,7 +454,7 @@ os_get_exec_path ()
 
 /**
  * @brief get the path to a specific GNUnet installation directory or,
 
 /**
  * @brief get the path to a specific GNUnet installation directory or,
- * with GNUNET_IPK_SELF_PREFIX, the current running apps installation directory
+ * with #GNUNET_OS_IPK_SELF_PREFIX, the current running apps installation directory
  * @author Milan
  * @return a pointer to the dir path (to be freed by the caller)
  */
  * @author Milan
  * @return a pointer to the dir path (to be freed by the caller)
  */
@@ -629,19 +627,24 @@ GNUNET_OS_installation_get_path (enum GNUNET_OS_InstallationPathKind dirkind)
 char *
 GNUNET_OS_get_libexec_binary_path (const char *progname)
 {
 char *
 GNUNET_OS_get_libexec_binary_path (const char *progname)
 {
+  static char *cache;
   char *libexecdir;
   char *binary;
 
   char *libexecdir;
   char *binary;
 
-  if (DIR_SEPARATOR == progname[0])
+  if ( (DIR_SEPARATOR == progname[0]) ||
+       (GNUNET_YES == GNUNET_STRINGS_path_is_absolute (progname, GNUNET_NO, NULL, NULL)) )
     return GNUNET_strdup (progname);
     return GNUNET_strdup (progname);
-  libexecdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBEXECDIR);
+  if (NULL != cache)
+    libexecdir = cache;
+  else
+    libexecdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBEXECDIR);
   if (NULL == libexecdir)
     return GNUNET_strdup (progname);
   GNUNET_asprintf (&binary,
                   "%s%s",
                   libexecdir,
                   progname);
   if (NULL == libexecdir)
     return GNUNET_strdup (progname);
   GNUNET_asprintf (&binary,
                   "%s%s",
                   libexecdir,
                   progname);
-  GNUNET_free (libexecdir);
+  cache = libexecdir;
   return binary;
 }
 
   return binary;
 }
 
@@ -654,12 +657,17 @@ GNUNET_OS_get_libexec_binary_path (const char *progname)
  *
  * @param binary the name of the file to check.
  *        W32: must not have an .exe suffix.
  *
  * @param binary the name of the file to check.
  *        W32: must not have an .exe suffix.
- * @return GNUNET_YES if the file is SUID,
- *         GNUNET_NO if not SUID (but binary exists)
- *         GNUNET_SYSERR on error (no such binary or not executable)
+ * @param check_suid input true if the binary should be checked for SUID (*nix)
+ *        W32: checks if the program has sufficient privileges by executing this
+ *             binary with the -d flag. -d omits a programs main loop and only
+ *             executes all privileged operations in an binary.
+ * @param params parameters used for w32 privilege checking (can be NULL for != w32 )
+ * @return #GNUNET_YES if the file is SUID (*nix) or can be executed with current privileges (W32),
+ *         #GNUNET_NO if not SUID (but binary exists),
+ *         #GNUNET_SYSERR on error (no such binary or not executable)
  */
 int
  */
 int
-GNUNET_OS_check_helper_binary (const char *binary)
+GNUNET_OS_check_helper_binary (const char *binary, int check_suid, const char *params)
 {
   struct stat statbuf;
   char *p;
 {
   struct stat statbuf;
   char *p;
@@ -701,7 +709,8 @@ GNUNET_OS_check_helper_binary (const char *binary)
 #endif
   if (NULL == p)
   {
 #endif
   if (NULL == p)
   {
-    LOG (GNUNET_ERROR_TYPE_INFO, _("Could not find binary `%s' in PATH!\n"),
+    LOG (GNUNET_ERROR_TYPE_INFO,
+         _("Could not find binary `%s' in PATH!\n"),
          binary);
     return GNUNET_SYSERR;
   }
          binary);
     return GNUNET_SYSERR;
   }
@@ -725,24 +734,64 @@ GNUNET_OS_check_helper_binary (const char *binary)
     GNUNET_free (p);
     return GNUNET_SYSERR;
   }
     GNUNET_free (p);
     return GNUNET_SYSERR;
   }
+  if (check_suid){
 #ifndef MINGW
 #ifndef MINGW
-  if ((0 != (statbuf.st_mode & S_ISUID)) && (0 == statbuf.st_uid))
-  {
-    GNUNET_free (p);
-    return GNUNET_YES;
-  }
-  /* binary exists, but not SUID */
+    if ((0 != (statbuf.st_mode & S_ISUID)) && (0 == statbuf.st_uid))
+    {
+      GNUNET_free (p);
+      return GNUNET_YES;
+    }
+    /* binary exists, but not SUID */
 #else
 #else
-  return GNUNET_YES;
-  /* FIXME: 
-   * no suid for windows possible!
-   * permissions-checking is too specific(as in non-portable)
-   * user/group checking is pointless (users/applications can drop privileges)
-   * using token checking for elevated permissions would limit gnunet
-   * to run only on winserver 2008 and 2012!
-   * 
-   * thus, ad add "dryrun" checking */
+    STARTUPINFO start;
+    char parameters[512];
+    PROCESS_INFORMATION proc;
+    DWORD exit_value;
+
+    GNUNET_snprintf (parameters,
+                    sizeof (parameters),
+                    "-d %s", params);
+    memset (&start, 0, sizeof (start));
+    start.cb = sizeof (start);
+    memset (&proc, 0, sizeof (proc));
+
+
+    // Start the child process.
+    if ( ! (CreateProcess( p,   // current windows (2k3 and up can handle / instead of \ in paths))
+        parameters,           // execute dryrun/priviliege checking mode
+        NULL,           // Process handle not inheritable
+        NULL,           // Thread handle not inheritable
+        FALSE,          // Set handle inheritance to FALSE
+        CREATE_DEFAULT_ERROR_MODE, // No creation flags
+        NULL,           // Use parent's environment block
+        NULL,           // Use parent's starting directory
+        &start,            // Pointer to STARTUPINFO structure
+        &proc )           // Pointer to PROCESS_INFORMATION structure
+                               ))
+      {
+        LOG (GNUNET_ERROR_TYPE_ERROR,
+             _("CreateProcess failed for binary %s (%d).\n"),
+             p, GetLastError());
+        return GNUNET_SYSERR;
+    }
+
+    // Wait until child process exits.
+    WaitForSingleObject( proc.hProcess, INFINITE );
+
+    if ( ! GetExitCodeProcess (proc.hProcess, &exit_value)){
+        LOG (GNUNET_ERROR_TYPE_ERROR,
+             _("GetExitCodeProcess failed for binary %s (%d).\n"),
+             p, GetLastError() );
+        return GNUNET_SYSERR;
+      }
+    // Close process and thread handles.
+    CloseHandle( proc.hProcess );
+    CloseHandle( proc.hThread );
+
+    if (!exit_value)
+      return GNUNET_YES;
 #endif
 #endif
+    }
   GNUNET_free (p);
   return GNUNET_NO;
 }
   GNUNET_free (p);
   return GNUNET_NO;
 }