- don't append libexec path to absolute paths
[oweals/gnunet.git] / src / util / os_installation.c
1 /*
2      This file is part of GNUnet.
3      (C) 2006 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file src/util/os_installation.c
23  * @brief get paths used by the program
24  * @author Milan
25  */
26 #include <sys/stat.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <unistr.h> /* for u16_to_u8 */
31
32 #include "platform.h"
33 #include "gnunet_common.h"
34 #include "gnunet_configuration_lib.h"
35 #include "gnunet_disk_lib.h"
36 #include "gnunet_os_lib.h"
37 #include "gnunet_strings_lib.h"
38 #if DARWIN
39 #include <mach-o/ldsyms.h>
40 #include <mach-o/dyld.h>
41 #elif WINDOWS
42 #include <windows.h>
43 #endif
44
45
46 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
47
48 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
49
50 #if LINUX
51 /**
52  * Try to determine path by reading /proc/PID/exe
53  *
54  * @return NULL on error
55  */
56 static char *
57 get_path_from_proc_maps ()
58 {
59   char fn[64];
60   char line[1024];
61   char dir[1024];
62   FILE *f;
63   char *lgu;
64
65   GNUNET_snprintf (fn, sizeof (fn), "/proc/%u/maps", getpid ());
66   if (NULL == (f = FOPEN (fn, "r")))
67     return NULL;
68   while (NULL != fgets (line, sizeof (line), f))
69   {
70     if ((1 ==
71          SSCANF (line, "%*x-%*x %*c%*c%*c%*c %*x %*2u:%*2u %*u%*[ ]%1023s", dir)) &&
72         (NULL != (lgu = strstr (dir, "libgnunetutil"))))
73     {
74       lgu[0] = '\0';
75       FCLOSE (f);
76       return GNUNET_strdup (dir);
77     }
78   }
79   FCLOSE (f);
80   return NULL;
81 }
82
83
84 /**
85  * Try to determine path by reading /proc/PID/exe
86  *
87  * @return NULL on error
88  */
89 static char *
90 get_path_from_proc_exe ()
91 {
92   char fn[64];
93   char lnk[1024];
94   ssize_t size;
95
96   GNUNET_snprintf (fn, sizeof (fn), "/proc/%u/exe", getpid ());
97   size = readlink (fn, lnk, sizeof (lnk) - 1);
98   if (size <= 0)
99   {
100     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "readlink", fn);
101     return NULL;
102   }
103   GNUNET_assert (size < sizeof (lnk));
104   lnk[size] = '\0';
105   while ((lnk[size] != '/') && (size > 0))
106     size--;
107   /* test for being in lib/gnunet/libexec/ */
108   if ( (size > strlen ("/gnunet/libexec/")) &&
109        (0 == strcmp ("/gnunet/libexec/",
110                      &lnk[size - strlen ("/gnunet/libexec/")])) )
111     size -= strlen ("gnunet/libexec/");
112   if ((size < 4) || (lnk[size - 4] != '/'))
113   {
114     /* not installed in "/bin/" -- binary path probably useless */
115     return NULL;
116   }
117   lnk[size] = '\0';
118   return GNUNET_strdup (lnk);
119 }
120 #endif
121
122 #if WINDOWS
123
124 static HINSTANCE dll_instance;
125
126
127 /* GNUNET_util_cl_init() in common_logging.c is preferred.
128  * This function is only for thread-local storage (not used in GNUnet)
129  * and hInstance saving.
130  */
131 BOOL WINAPI
132 DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
133 {
134   switch (fdwReason)
135   {
136     case DLL_PROCESS_ATTACH:
137       dll_instance = hinstDLL;
138       break;
139     case DLL_THREAD_ATTACH:
140       break;
141     case DLL_THREAD_DETACH:
142       break;
143     case DLL_PROCESS_DETACH:
144       break;
145   }
146   return TRUE;
147 }
148
149
150 /**
151  * Try to determine path with win32-specific function
152  *
153  * @return NULL on error
154  */
155 static char *
156 get_path_from_module_filename ()
157 {
158   size_t pathlen = 512;
159   DWORD real_pathlen;
160   wchar_t *idx;
161   wchar_t *modulepath = NULL;
162   char *upath;
163   uint8_t *u8_string;
164   size_t u8_string_length;
165
166   /* This braindead function won't tell us how much space it needs, so
167    * we start at 1024 and double the space up if it doesn't fit, until
168    * it fits, or we exceed the threshold.
169    */
170   do
171   {
172     pathlen = pathlen * 2;
173     modulepath = GNUNET_realloc (modulepath, pathlen * sizeof (wchar_t));
174     SetLastError (0);
175     real_pathlen = GetModuleFileNameW (dll_instance, modulepath, pathlen * sizeof (wchar_t));
176   } while (real_pathlen >= pathlen && pathlen < 16*1024);
177   if (real_pathlen >= pathlen)
178     GNUNET_abort ();
179   /* To be safe */
180   modulepath[real_pathlen] = '\0';
181
182   idx = modulepath + real_pathlen;
183   while ((idx > modulepath) && (*idx != L'\\') && (*idx != L'/'))
184     idx--;
185   *idx = L'\0';
186
187   /* Now modulepath holds full path to the directory where libgnunetutil is.
188    * This directory should look like <GNUNET_PREFIX>/bin or <GNUNET_PREFIX>.
189    */
190   if (wcschr (modulepath, L'/') || wcschr (modulepath, L'\\'))
191   {
192     /* At least one directory component (i.e. we're not in a root directory) */
193     wchar_t *dirname = idx;
194     while ((dirname > modulepath) && (*dirname != L'\\') && (*dirname != L'/'))
195       dirname--;
196     *dirname = L'\0';
197     if (dirname > modulepath)
198     {
199       dirname++;
200       /* Now modulepath holds full path to the parent directory of the directory
201        * where libgnunetutil is.
202        * dirname holds the name of the directory where libgnunetutil is.
203        */
204       if (wcsicmp (dirname, L"bin") == 0)
205       {
206         /* pass */
207       }
208       else
209       {
210         /* Roll back our changes to modulepath */
211         dirname--;
212         *dirname = L'/';
213       }
214     }
215   }
216
217   /* modulepath is GNUNET_PREFIX */
218   u8_string = u16_to_u8 (modulepath, wcslen (modulepath), NULL, &u8_string_length);
219   if (NULL == u8_string)
220     GNUNET_abort ();
221
222   upath = GNUNET_malloc (u8_string_length + 1);
223   memcpy (upath, u8_string, u8_string_length);
224   upath[u8_string_length] = '\0';
225
226   free (u8_string);
227   GNUNET_free (modulepath);
228
229   return upath;
230 }
231 #endif
232
233 #if DARWIN
234 /**
235  * Signature of the '_NSGetExecutablePath" function.
236  *
237  * @param buf where to write the path
238  * @param number of bytes available in 'buf'
239  * @return 0 on success, otherwise desired number of bytes is stored in 'bufsize'
240  */
241 typedef int (*MyNSGetExecutablePathProto) (char *buf, size_t * bufsize);
242
243
244 /**
245  * Try to obtain the path of our executable using '_NSGetExecutablePath'.
246  *
247  * @return NULL on error
248  */
249 static char *
250 get_path_from_NSGetExecutablePath ()
251 {
252   static char zero = '\0';
253   char *path;
254   size_t len;
255   MyNSGetExecutablePathProto func;
256
257   path = NULL;
258   if (NULL == (func =
259                (MyNSGetExecutablePathProto) dlsym (RTLD_DEFAULT, "_NSGetExecutablePath")))
260     return NULL;
261   path = &zero;
262   len = 0;
263   /* get the path len, including the trailing \0 */
264   (void) func (path, &len);
265   if (0 == len)
266     return NULL;
267   path = GNUNET_malloc (len);
268   if (0 != func (path, &len))
269   {
270     GNUNET_free (path);
271     return NULL;
272   }
273   len = strlen (path);
274   while ((path[len] != '/') && (len > 0))
275     len--;
276   path[len] = '\0';
277   return path;
278 }
279
280
281 /**
282  * Try to obtain the path of our executable using '_dyld_image' API.
283  *
284  * @return NULL on error
285  */
286 static char *
287 get_path_from_dyld_image ()
288 {
289   const char *path;
290   char *p;
291   char *s;
292   unsigned int i;
293   int c;
294
295   c = _dyld_image_count ();
296   for (i = 0; i < c; i++)
297   {
298     if (_dyld_get_image_header (i) != &_mh_dylib_header)
299       continue;
300     path = _dyld_get_image_name (i);
301     if ( (NULL == path) || (0 == strlen (path)) )
302       continue;
303     p = GNUNET_strdup (path);
304     s = p + strlen (p);
305     while ((s > p) && ('/' != *s))
306       s--;
307     s++;
308     *s = '\0';
309     return p;
310   }
311   return NULL;
312 }
313 #endif
314
315
316 /**
317  * Return the actual path to a file found in the current
318  * PATH environment variable.
319  *
320  * @param binary the name of the file to find
321  * @return path to binary, NULL if not found
322  */
323 static char *
324 get_path_from_PATH (const char *binary)
325 {
326   char *path;
327   char *pos;
328   char *end;
329   char *buf;
330   const char *p;
331
332   if (NULL == (p = getenv ("PATH")))
333     return NULL;
334 #if WINDOWS
335   /* On W32 look in CWD first. */
336   GNUNET_asprintf (&path, ".%c%s", PATH_SEPARATOR, p);
337 #else
338   path = GNUNET_strdup (p);     /* because we write on it */
339 #endif
340   buf = GNUNET_malloc (strlen (path) + strlen (binary) + 1 + 1);
341   pos = path;
342   while (NULL != (end = strchr (pos, PATH_SEPARATOR)))
343   {
344     *end = '\0';
345     sprintf (buf, "%s/%s", pos, binary);
346     if (GNUNET_DISK_file_test (buf) == GNUNET_YES)
347     {
348       pos = GNUNET_strdup (pos);
349       GNUNET_free (buf);
350       GNUNET_free (path);
351       return pos;
352     }
353     pos = end + 1;
354   }
355   sprintf (buf, "%s/%s", pos, binary);
356   if (GNUNET_YES == GNUNET_DISK_file_test (buf))
357   {
358     pos = GNUNET_strdup (pos);
359     GNUNET_free (buf);
360     GNUNET_free (path);
361     return pos;
362   }
363   GNUNET_free (buf);
364   GNUNET_free (path);
365   return NULL;
366 }
367
368
369 /**
370  * Try to obtain the installation path using the "GNUNET_PREFIX" environment
371  * variable.
372  *
373  * @return NULL on error (environment variable not set)
374  */
375 static char *
376 get_path_from_GNUNET_PREFIX ()
377 {
378   const char *p;
379
380   if (NULL != (p = getenv ("GNUNET_PREFIX")))
381     return GNUNET_strdup (p);
382   return NULL;
383 }
384
385
386 /**
387  * @brief get the path to GNUnet bin/ or lib/, prefering the lib/ path
388  * @author Milan
389  *
390  * @return a pointer to the executable path, or NULL on error
391  */
392 static char *
393 os_get_gnunet_path ()
394 {
395   char *ret;
396
397   if (NULL != (ret = get_path_from_GNUNET_PREFIX ()))
398     return ret;
399 #if LINUX
400   if (NULL != (ret = get_path_from_proc_maps ()))
401     return ret;
402   /* try path *first*, before /proc/exe, as /proc/exe can be wrong */
403   if (NULL != (ret = get_path_from_PATH ("gnunet-arm")))
404     return ret;
405   if (NULL != (ret = get_path_from_proc_exe ()))
406     return ret;
407 #endif
408 #if WINDOWS
409   if (NULL != (ret = get_path_from_module_filename ()))
410     return ret;
411 #endif
412 #if DARWIN
413   if (NULL != (ret = get_path_from_dyld_image ()))
414     return ret;
415   if (NULL != (ret = get_path_from_NSGetExecutablePath ()))
416     return ret;
417 #endif
418   if (NULL != (ret = get_path_from_PATH ("gnunet-arm")))
419     return ret;
420   /* other attempts here */
421   LOG (GNUNET_ERROR_TYPE_ERROR,
422        _
423        ("Could not determine installation path for %s.  Set `%s' environment variable.\n"),
424        "GNUnet", "GNUNET_PREFIX");
425   return NULL;
426 }
427
428
429 /**
430  * @brief get the path to current app's bin/
431  * @author Milan
432  *
433  * @return a pointer to the executable path, or NULL on error
434  */
435 static char *
436 os_get_exec_path ()
437 {
438   char *ret = NULL;
439
440 #if LINUX
441   if (NULL != (ret = get_path_from_proc_exe ()))
442     return ret;
443 #endif
444 #if WINDOWS
445   if (NULL != (ret = get_path_from_module_filename ()))
446     return ret;
447 #endif
448 #if DARWIN
449   if (NULL != (ret = get_path_from_NSGetExecutablePath ()))
450     return ret;
451 #endif
452   /* other attempts here */
453   return ret;
454 }
455
456
457 /**
458  * @brief get the path to a specific GNUnet installation directory or,
459  * with GNUNET_IPK_SELF_PREFIX, the current running apps installation directory
460  * @author Milan
461  * @return a pointer to the dir path (to be freed by the caller)
462  */
463 char *
464 GNUNET_OS_installation_get_path (enum GNUNET_OS_InstallationPathKind dirkind)
465 {
466   size_t n;
467   const char *dirname;
468   char *execpath = NULL;
469   char *tmp;
470   int isbasedir;
471
472   /* if wanted, try to get the current app's bin/ */
473   if (dirkind == GNUNET_OS_IPK_SELF_PREFIX)
474     execpath = os_get_exec_path ();
475
476   /* try to get GNUnet's bin/ or lib/, or if previous was unsuccessful some
477    * guess for the current app */
478   if (NULL == execpath)
479     execpath = os_get_gnunet_path ();
480
481   if (NULL == execpath)
482     return NULL;
483
484   n = strlen (execpath);
485   if (0 == n)
486   {
487     /* should never happen, but better safe than sorry */
488     GNUNET_free (execpath);
489     return NULL;
490   }
491   /* remove filename itself */
492   while ((n > 1) && (DIR_SEPARATOR == execpath[n - 1]))
493     execpath[--n] = '\0';
494
495   isbasedir = 1;
496   if ((n > 6) &&
497       ((0 == strcasecmp (&execpath[n - 6], "/lib32")) ||
498        (0 == strcasecmp (&execpath[n - 6], "/lib64"))))
499   {
500     if ( (GNUNET_OS_IPK_LIBDIR != dirkind) &&
501          (GNUNET_OS_IPK_LIBEXECDIR != dirkind) )
502     {
503       /* strip '/lib32' or '/lib64' */
504       execpath[n - 6] = '\0';
505       n -= 6;
506     }
507     else
508       isbasedir = 0;
509   }
510   else if ((n > 4) &&
511            ((0 == strcasecmp (&execpath[n - 4], "/bin")) ||
512             (0 == strcasecmp (&execpath[n - 4], "/lib"))))
513   {
514     /* strip '/bin' or '/lib' */
515     execpath[n - 4] = '\0';
516     n -= 4;
517   }
518   /* in case this was a directory named foo-bin, remove "foo-" */
519   while ((n > 1) && (execpath[n - 1] == DIR_SEPARATOR))
520     execpath[--n] = '\0';
521   switch (dirkind)
522   {
523   case GNUNET_OS_IPK_PREFIX:
524   case GNUNET_OS_IPK_SELF_PREFIX:
525     dirname = DIR_SEPARATOR_STR;
526     break;
527   case GNUNET_OS_IPK_BINDIR:
528     dirname = DIR_SEPARATOR_STR "bin" DIR_SEPARATOR_STR;
529     break;
530   case GNUNET_OS_IPK_LIBDIR:
531     if (isbasedir)
532     {
533       dirname =
534           DIR_SEPARATOR_STR "lib" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR;
535       tmp = GNUNET_malloc (strlen (execpath) + strlen (dirname) + 1);
536       sprintf (tmp, "%s%s", execpath, dirname);
537       if ( (GNUNET_YES !=
538             GNUNET_DISK_directory_test (tmp, GNUNET_YES)) &&
539            (4 == sizeof (void *)) )
540       {
541         GNUNET_free (tmp);
542         dirname =
543           DIR_SEPARATOR_STR "lib32" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR;
544         tmp = GNUNET_malloc (strlen (execpath) + strlen (dirname) + 1);
545         sprintf (tmp, "%s%s", execpath, dirname);
546       }
547       if ( (GNUNET_YES !=
548             GNUNET_DISK_directory_test (tmp, GNUNET_YES)) &&
549            (8 == sizeof (void *)) )
550       {
551         dirname =
552           DIR_SEPARATOR_STR "lib64" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR;
553       }
554       GNUNET_free (tmp);
555     }
556     else
557       dirname = DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR;
558     break;
559   case GNUNET_OS_IPK_DATADIR:
560     dirname =
561         DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR;
562     break;
563   case GNUNET_OS_IPK_LOCALEDIR:
564     dirname =
565         DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "locale" DIR_SEPARATOR_STR;
566     break;
567   case GNUNET_OS_IPK_ICONDIR:
568     dirname =
569         DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "icons" DIR_SEPARATOR_STR;
570     break;
571   case GNUNET_OS_IPK_DOCDIR:
572     dirname =
573         DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "doc" DIR_SEPARATOR_STR \
574         "gnunet" DIR_SEPARATOR_STR;
575     break;
576   case GNUNET_OS_IPK_LIBEXECDIR:
577     if (isbasedir)
578     {
579       dirname =
580         DIR_SEPARATOR_STR "lib" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR \
581         "libexec" DIR_SEPARATOR_STR;
582       tmp = GNUNET_malloc (strlen (execpath) + strlen (dirname) + 1);
583       sprintf (tmp, "%s%s", execpath, dirname);
584       if ( (GNUNET_YES !=
585             GNUNET_DISK_directory_test (tmp, GNUNET_YES)) &&
586            (4 == sizeof (void *)) )
587       {
588         GNUNET_free (tmp);
589         dirname =
590           DIR_SEPARATOR_STR "lib32" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR \
591           "libexec" DIR_SEPARATOR_STR;
592         tmp = GNUNET_malloc (strlen (execpath) + strlen (dirname) + 1);
593         sprintf (tmp, "%s%s", execpath, dirname);
594       }
595       if ( (GNUNET_YES !=
596             GNUNET_DISK_directory_test (tmp, GNUNET_YES)) &&
597            (8 == sizeof (void *)) )
598       {
599         dirname =
600           DIR_SEPARATOR_STR "lib64" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR \
601           "libexec" DIR_SEPARATOR_STR;
602       }
603       GNUNET_free (tmp);
604     }
605     else
606       dirname =
607         DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR \
608         "libexec" DIR_SEPARATOR_STR;
609     break;
610   default:
611     GNUNET_free (execpath);
612     return NULL;
613   }
614   tmp = GNUNET_malloc (strlen (execpath) + strlen (dirname) + 1);
615   sprintf (tmp, "%s%s", execpath, dirname);
616   GNUNET_free (execpath);
617   return tmp;
618 }
619
620
621 /**
622  * Given the name of a gnunet-helper, gnunet-service or gnunet-daemon
623  * binary, try to prefix it with the libexec/-directory to get the
624  * full path.
625  *
626  * @param progname name of the binary
627  * @return full path to the binary, if possible, otherwise copy of 'progname'
628  */
629 char *
630 GNUNET_OS_get_libexec_binary_path (const char *progname)
631 {
632   char *libexecdir;
633   char *binary;
634
635   if (DIR_SEPARATOR == progname[0])
636     return GNUNET_strdup (progname);
637   if (GNUNET_YES == GNUNET_STRINGS_path_is_absolute (progname, GNUNET_NO, NULL, NULL))
638     return GNUNET_strdup (progname);
639   libexecdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBEXECDIR);
640   if (NULL == libexecdir)
641     return GNUNET_strdup (progname);
642   GNUNET_asprintf (&binary,
643                    "%s%s",
644                    libexecdir,
645                    progname);
646   GNUNET_free (libexecdir);
647   return binary;
648 }
649
650
651 /**
652  * Check whether an executable exists and possibly
653  * if the suid bit is set on the file.
654  * Attempts to find the file using the current
655  * PATH environment variable as a search path.
656  *
657  * @param binary the name of the file to check.
658  *        W32: must not have an .exe suffix.
659  * @param check_suid input true if the binary should be checked for SUID (*nix)
660  *        W32: checks if the program has sufficient privileges by executing this
661  *             binary with the -d flag. -d omits a programs main loop and only
662  *             executes all privileged operations in an binary.
663  * @param params parameters used for w32 privilege checking (can be NULL for != w32 )
664  * @return GNUNET_YES if the file is SUID (*nix) or can be executed with current privileges (W32),
665  *         GNUNET_NO if not SUID (but binary exists),
666  *         GNUNET_SYSERR on error (no such binary or not executable)
667  */
668 int
669 GNUNET_OS_check_helper_binary (const char *binary, int check_suid, const char *params)
670 {
671   struct stat statbuf;
672   char *p;
673   char *pf;
674 #ifdef MINGW
675   char *binaryexe;
676
677   GNUNET_asprintf (&binaryexe, "%s.exe", binary);
678   if ( (GNUNET_YES == GNUNET_STRINGS_path_is_absolute (binaryexe, GNUNET_NO,
679                                                        NULL, NULL)) ||
680        (0 == strncmp (binary, "./", 2)) )
681     p = GNUNET_strdup (binaryexe);
682   else
683   {
684     p = get_path_from_PATH (binaryexe);
685     if (NULL != p)
686     {
687       GNUNET_asprintf (&pf, "%s/%s", p, binaryexe);
688       GNUNET_free (p);
689       p = pf;
690     }
691   }
692   GNUNET_free (binaryexe);
693 #else
694   if ( (GNUNET_YES == GNUNET_STRINGS_path_is_absolute (binary, GNUNET_NO,
695                                                        NULL, NULL)) ||
696        (0 == strncmp (binary, "./", 2)) )
697     p = GNUNET_strdup (binary);
698   else
699   {
700     p = get_path_from_PATH (binary);
701     if (NULL != p)
702     {
703       GNUNET_asprintf (&pf, "%s/%s", p, binary);
704       GNUNET_free (p);
705       p = pf;
706     }
707   }
708 #endif
709   if (NULL == p)
710   {
711     LOG (GNUNET_ERROR_TYPE_INFO, _("Could not find binary `%s' in PATH!\n"),
712          binary);
713     return GNUNET_SYSERR;
714   }
715   if (0 != ACCESS (p, X_OK))
716   {
717     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", p);
718     GNUNET_free (p);
719     return GNUNET_SYSERR;
720   }
721 #ifndef MINGW
722   if (0 == getuid ())
723   {
724     /* as we run as root, we don't insist on SUID */
725     GNUNET_free (p);
726     return GNUNET_OK;
727   }
728 #endif
729   if (0 != STAT (p, &statbuf))
730   {
731     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", p);
732     GNUNET_free (p);
733     return GNUNET_SYSERR;
734   }
735   if (check_suid){
736 #ifndef MINGW
737     if ((0 != (statbuf.st_mode & S_ISUID)) && (0 == statbuf.st_uid))
738     {
739       GNUNET_free (p);
740       return GNUNET_YES;
741     }
742     /* binary exists, but not SUID */
743 #else
744     STARTUPINFO start;
745     char parameters[512];
746     PROCESS_INFORMATION proc;
747     DWORD exit_value;
748     
749     GNUNET_snprintf (parameters, 
750                      sizeof (parameters), 
751                      "-d %s", params);
752     memset (&start, 0, sizeof (start));
753     start.cb = sizeof (start);
754     memset (&proc, 0, sizeof (proc));
755
756             
757     // Start the child process. 
758     if ( ! (CreateProcess( p,   // current windows (2k3 and up can handle / instead of \ in paths))
759         parameters,           // execute dryrun/priviliege checking mode
760         NULL,           // Process handle not inheritable
761         NULL,           // Thread handle not inheritable
762         FALSE,          // Set handle inheritance to FALSE
763         CREATE_DEFAULT_ERROR_MODE, // No creation flags
764         NULL,           // Use parent's environment block
765         NULL,           // Use parent's starting directory 
766         &start,            // Pointer to STARTUPINFO structure
767         &proc )           // Pointer to PROCESS_INFORMATION structure
768                                )) 
769       {
770         LOG (GNUNET_ERROR_TYPE_ERROR, 
771              _("CreateProcess failed for binary %s (%d).\n"),
772              p, GetLastError());
773         return GNUNET_SYSERR;
774     }
775
776     // Wait until child process exits.
777     WaitForSingleObject( proc.hProcess, INFINITE );
778     
779     if ( ! GetExitCodeProcess (proc.hProcess, &exit_value)){
780         LOG (GNUNET_ERROR_TYPE_ERROR, 
781              _("GetExitCodeProcess failed for binary %s (%d).\n"), 
782              p, GetLastError() );
783         return GNUNET_SYSERR;
784       }
785     // Close process and thread handles. 
786     CloseHandle( proc.hProcess );
787     CloseHandle( proc.hThread );
788   
789     if (!exit_value)
790       return GNUNET_YES;
791 #endif
792     }
793   GNUNET_free (p);
794   return GNUNET_NO;
795 }
796
797
798 /* end of os_installation.c */