aboutsummaryrefslogtreecommitdiff
path: root/src/lib/util/os_installation.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/util/os_installation.c')
-rw-r--r--src/lib/util/os_installation.c829
1 files changed, 829 insertions, 0 deletions
diff --git a/src/lib/util/os_installation.c b/src/lib/util/os_installation.c
new file mode 100644
index 000000000..ff04a8a7f
--- /dev/null
+++ b/src/lib/util/os_installation.c
@@ -0,0 +1,829 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2006-2018, 2022 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file src/util/os_installation.c
23 * @brief get paths used by the program
24 * @author Milan
25 * @author Christian Fuchs
26 * @author Christian Grothoff
27 * @author Matthias Wachs
28 * @author Heikki Lindholm
29 * @author LRN
30 */
31#include "platform.h"
32#include <sys/stat.h>
33#include <stdlib.h>
34#include <string.h>
35#include <unistd.h>
36#include <unistr.h> /* for u16_to_u8 */
37
38
39#include "gnunet_util_lib.h"
40#if DARWIN
41#include <mach-o/ldsyms.h>
42#include <mach-o/dyld.h>
43#endif
44
45
46#define LOG(kind, ...) \
47 GNUNET_log_from (kind, "util-os-installation", __VA_ARGS__)
48
49#define LOG_STRERROR_FILE(kind, syscall, filename) \
50 GNUNET_log_from_strerror_file (kind, \
51 "util-os-installation", \
52 syscall, \
53 filename)
54
55
56/**
57 * Default project data used for installation path detection
58 * for GNUnet (core).
59 */
60static const struct GNUNET_OS_ProjectData default_pd = {
61 .libname = "libgnunetutil",
62 .project_dirname = "gnunet",
63 .binary_name = "gnunet-arm",
64 .version = PACKAGE_VERSION " " VCS_VERSION,
65 .env_varname = "GNUNET_PREFIX",
66 .base_config_varname = "GNUNET_BASE_CONFIG",
67 .bug_email = "gnunet-developers@gnu.org",
68 .homepage = "http://www.gnu.org/s/gnunet/",
69 .config_file = "gnunet.conf",
70 .user_config_file = "~/.config/gnunet.conf",
71 .is_gnu = 1,
72 .gettext_domain = "gnunet",
73 .gettext_path = NULL,
74 .agpl_url = GNUNET_AGPL_URL,
75};
76
77/**
78 * Which project data do we currently use for installation
79 * path detection? Never NULL.
80 */
81static const struct GNUNET_OS_ProjectData *current_pd = &default_pd;
82
83/**
84 * PD for which gettext has been initialized last.
85 * Note that the gettext initialization done within
86 * GNUNET_PROGRAM_run2 is for the specific application.
87 */
88static const struct GNUNET_OS_ProjectData *gettextinit;
89
90
91/**
92 * Return default project data used by 'libgnunetutil' for GNUnet.
93 */
94const struct GNUNET_OS_ProjectData *
95GNUNET_OS_project_data_default (void)
96{
97 return &default_pd;
98}
99
100
101/**
102 * @return current project data.
103 */
104const struct GNUNET_OS_ProjectData *
105GNUNET_OS_project_data_get ()
106{
107 if (current_pd != gettextinit)
108 {
109 char *path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LOCALEDIR);
110
111 if (NULL != path)
112 bindtextdomain (PACKAGE,
113 path);
114 GNUNET_free (path);
115 gettextinit = current_pd;
116 }
117 return current_pd;
118}
119
120
121void
122GNUNET_OS_init (const struct GNUNET_OS_ProjectData *pd)
123{
124 GNUNET_assert (NULL != pd);
125 current_pd = pd;
126 if (pd != gettextinit)
127 {
128 char *path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LOCALEDIR);
129
130 if (NULL != path)
131 bindtextdomain (PACKAGE,
132 path);
133 GNUNET_free (path);
134 gettextinit = pd;
135 }
136}
137
138
139#ifdef __linux__
140/**
141 * Try to determine path by reading /proc/PID/exe
142 *
143 * @return NULL on error
144 */
145static char *
146get_path_from_proc_maps (void)
147{
148 char fn[64];
149 char line[1024];
150 char dir[1024];
151 FILE *f;
152 char *lgu;
153
154 if (NULL == current_pd->libname)
155 return NULL;
156 GNUNET_snprintf (fn,
157 sizeof(fn),
158 "/proc/%u/maps",
159 getpid ());
160 if (NULL == (f = fopen (fn, "r")))
161 return NULL;
162 while (NULL != fgets (line, sizeof(line), f))
163 {
164 if ((1 == sscanf (line,
165 "%*p-%*p %*c%*c%*c%*c %*x %*x:%*x %*u%*[ ]%1023s",
166 dir)) &&
167 (NULL != (lgu = strstr (dir,
168 current_pd->libname))))
169 {
170 lgu[0] = '\0';
171 fclose (f);
172 return GNUNET_strdup (dir);
173 }
174 }
175 fclose (f);
176 return NULL;
177}
178
179
180/**
181 * Try to determine path by reading /proc/PID/exe
182 *
183 * @return NULL on error
184 */
185static char *
186get_path_from_proc_exe (void)
187{
188 char fn[64];
189 char lnk[1024];
190 ssize_t size;
191 char *lep;
192
193 GNUNET_snprintf (fn, sizeof(fn), "/proc/%u/exe", getpid ());
194 size = readlink (fn, lnk, sizeof(lnk) - 1);
195 if (size <= 0)
196 {
197 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "readlink", fn);
198 return NULL;
199 }
200 GNUNET_assert (((size_t) size) < sizeof(lnk));
201 lnk[size] = '\0';
202 while ((lnk[size] != '/') && (size > 0))
203 size--;
204 GNUNET_asprintf (&lep, "/%s/libexec/", current_pd->project_dirname);
205 /* test for being in lib/gnunet/libexec/ or lib/MULTIARCH/gnunet/libexec */
206 if ((((size_t) size) > strlen (lep)) &&
207 (0 == strcmp (lep, &lnk[size - strlen (lep)])))
208 size -= strlen (lep) - 1;
209 GNUNET_free (lep);
210 if ((size < 4) || (lnk[size - 4] != '/'))
211 {
212 /* not installed in "/bin/" -- binary path probably useless */
213 return NULL;
214 }
215 lnk[size] = '\0';
216 return GNUNET_strdup (lnk);
217}
218
219
220#endif
221
222
223#if DARWIN
224/**
225 * Signature of the '_NSGetExecutablePath" function.
226 *
227 * @param buf where to write the path
228 * @param number of bytes available in @a buf
229 * @return 0 on success, otherwise desired number of bytes is stored in 'bufsize'
230 */
231typedef int (*MyNSGetExecutablePathProto) (char *buf, size_t *bufsize);
232
233
234/**
235 * Try to obtain the path of our executable using '_NSGetExecutablePath'.
236 *
237 * @return NULL on error
238 */
239static char *
240get_path_from_NSGetExecutablePath (void)
241{
242 static char zero = '\0';
243 char *path;
244 size_t len;
245 MyNSGetExecutablePathProto func;
246
247 path = NULL;
248 if (NULL ==
249 (func = (MyNSGetExecutablePathProto) dlsym (RTLD_DEFAULT,
250 "_NSGetExecutablePath")))
251 return NULL;
252 path = &zero;
253 len = 0;
254 /* get the path len, including the trailing \0 */
255 (void) func (path, &len);
256 if (0 == len)
257 return NULL;
258 path = GNUNET_malloc (len);
259 if (0 != func (path, &len))
260 {
261 GNUNET_free (path);
262 return NULL;
263 }
264 len = strlen (path);
265 while ((path[len] != '/') && (len > 0))
266 len--;
267 path[len] = '\0';
268 return path;
269}
270
271
272/**
273 * Try to obtain the path of our executable using '_dyld_image' API.
274 *
275 * @return NULL on error
276 */
277static char *
278get_path_from_dyld_image (void)
279{
280 const char *path;
281 char *p;
282 char *s;
283 unsigned int i;
284 int c;
285
286 c = _dyld_image_count ();
287 for (i = 0; i < c; i++)
288 {
289 if (((const void *) _dyld_get_image_header (i)) !=
290 ((const void *) &_mh_dylib_header))
291 continue;
292 path = _dyld_get_image_name (i);
293 if ((NULL == path) || (0 == strlen (path)))
294 continue;
295 p = GNUNET_strdup (path);
296 s = p + strlen (p);
297 while ((s > p) && ('/' != *s))
298 s--;
299 s++;
300 *s = '\0';
301 return p;
302 }
303 return NULL;
304}
305
306
307#endif
308
309
310/**
311 * Return the actual path to a file found in the current
312 * PATH environment variable.
313 *
314 * @param binary the name of the file to find
315 * @return path to binary, NULL if not found
316 */
317static char *
318get_path_from_PATH (const char *binary)
319{
320 char *path;
321 char *pos;
322 char *end;
323 char *buf;
324 const char *p;
325
326 if (NULL == (p = getenv ("PATH")))
327 return NULL;
328
329 path = GNUNET_strdup (p); /* because we write on it */
330
331 buf = GNUNET_malloc (strlen (path) + strlen (binary) + 1 + 1);
332 pos = path;
333 while (NULL != (end = strchr (pos, PATH_SEPARATOR)))
334 {
335 *end = '\0';
336 sprintf (buf, "%s/%s", pos, binary);
337 if (GNUNET_DISK_file_test (buf) == GNUNET_YES)
338 {
339 pos = GNUNET_strdup (pos);
340 GNUNET_free (buf);
341 GNUNET_free (path);
342 return pos;
343 }
344 pos = end + 1;
345 }
346 sprintf (buf, "%s/%s", pos, binary);
347 if (GNUNET_YES == GNUNET_DISK_file_test (buf))
348 {
349 pos = GNUNET_strdup (pos);
350 GNUNET_free (buf);
351 GNUNET_free (path);
352 return pos;
353 }
354 GNUNET_free (buf);
355 GNUNET_free (path);
356 return NULL;
357}
358
359
360/**
361 * Try to obtain the installation path using the "GNUNET_PREFIX" environment
362 * variable.
363 *
364 * @return NULL on error (environment variable not set)
365 */
366static char *
367get_path_from_GNUNET_PREFIX (void)
368{
369 const char *p;
370
371 if ((NULL != current_pd->env_varname) &&
372 (NULL != (p = getenv (current_pd->env_varname))))
373 return GNUNET_strdup (p);
374 if ((NULL != current_pd->env_varname_alt) &&
375 (NULL != (p = getenv (current_pd->env_varname_alt))))
376 return GNUNET_strdup (p);
377 return NULL;
378}
379
380
381/**
382 * @brief get the path to GNUnet bin/ or lib/, preferring the lib/ path
383 * @author Milan
384 *
385 * @return a pointer to the executable path, or NULL on error
386 */
387static char *
388os_get_gnunet_path (void)
389{
390 char *ret;
391
392 if (NULL != (ret = get_path_from_GNUNET_PREFIX ()))
393 return ret;
394#ifdef __linux__
395 if (NULL != (ret = get_path_from_proc_maps ()))
396 return ret;
397 /* try path *first*, before /proc/exe, as /proc/exe can be wrong */
398 if ((NULL != current_pd->binary_name) &&
399 (NULL != (ret = get_path_from_PATH (current_pd->binary_name))))
400 return ret;
401 if (NULL != (ret = get_path_from_proc_exe ()))
402 return ret;
403#endif
404#if DARWIN
405 if (NULL != (ret = get_path_from_dyld_image ()))
406 return ret;
407 if (NULL != (ret = get_path_from_NSGetExecutablePath ()))
408 return ret;
409#endif
410 if ((NULL != current_pd->binary_name) &&
411 (NULL != (ret = get_path_from_PATH (current_pd->binary_name))))
412 return ret;
413 /* other attempts here */
414 LOG (GNUNET_ERROR_TYPE_ERROR,
415 _ (
416 "Could not determine installation path for %s. Set `%s' environment variable.\n"),
417 current_pd->project_dirname,
418 current_pd->env_varname);
419 return NULL;
420}
421
422
423/**
424 * @brief get the path to current app's bin/
425 * @return a pointer to the executable path, or NULL on error
426 */
427static char *
428os_get_exec_path ()
429{
430 char *ret = NULL;
431
432#ifdef __linux__
433 if (NULL != (ret = get_path_from_proc_exe ()))
434 return ret;
435#endif
436#if DARWIN
437 if (NULL != (ret = get_path_from_NSGetExecutablePath ()))
438 return ret;
439#endif
440 /* other attempts here */
441 return ret;
442}
443
444
445/**
446 * @brief get the path to a specific GNUnet installation directory or,
447 * with #GNUNET_OS_IPK_SELF_PREFIX, the current running apps installation directory
448 * @return a pointer to the dir path (to be freed by the caller)
449 */
450char *
451GNUNET_OS_installation_get_path (enum GNUNET_OS_InstallationPathKind dirkind)
452{
453 size_t n;
454 char *dirname;
455 char *execpath = NULL;
456 char *tmp;
457 char *multiarch;
458 char *libdir;
459 int isbasedir;
460
461 /* if wanted, try to get the current app's bin/ */
462 if (dirkind == GNUNET_OS_IPK_SELF_PREFIX)
463 execpath = os_get_exec_path ();
464
465 /* try to get GNUnet's bin/ or lib/, or if previous was unsuccessful some
466 * guess for the current app */
467 if (NULL == execpath)
468 execpath = os_get_gnunet_path ();
469 if (NULL == execpath)
470 return NULL;
471
472 n = strlen (execpath);
473 if (0 == n)
474 {
475 /* should never happen, but better safe than sorry */
476 GNUNET_free (execpath);
477 return NULL;
478 }
479 /* remove filename itself */
480 while ((n > 1) && (DIR_SEPARATOR == execpath[n - 1]))
481 execpath[--n] = '\0';
482
483 isbasedir = 1;
484 if ((n > 6) && ((0 == strcasecmp (&execpath[n - 6], "/lib32")) ||
485 (0 == strcasecmp (&execpath[n - 6], "/lib64"))))
486 {
487 if ((GNUNET_OS_IPK_LIBDIR != dirkind) &&
488 (GNUNET_OS_IPK_LIBEXECDIR != dirkind))
489 {
490 /* strip '/lib32' or '/lib64' */
491 execpath[n - 6] = '\0';
492 n -= 6;
493 }
494 else
495 isbasedir = 0;
496 }
497 else if ((n > 4) && ((0 == strcasecmp (&execpath[n - 4], "/bin")) ||
498 (0 == strcasecmp (&execpath[n - 4], "/lib"))))
499 {
500 /* strip '/bin' or '/lib' */
501 execpath[n - 4] = '\0';
502 n -= 4;
503 }
504 multiarch = NULL;
505 if (NULL != (libdir = strstr (execpath, "/lib/")))
506 {
507 /* test for multi-arch path of the form "PREFIX/lib/MULTIARCH/";
508 here we need to re-add 'multiarch' to lib and libexec paths later! */
509 multiarch = &libdir[5];
510 if (NULL == strchr (multiarch, '/'))
511 libdir[0] =
512 '\0'; /* Debian multiarch format, cut of from 'execpath' but preserve in multicarch */
513 else
514 multiarch =
515 NULL; /* maybe not, multiarch still has a '/', which is not OK */
516 }
517 /* in case this was a directory named foo-bin, remove "foo-" */
518 while ((n > 1) && (execpath[n - 1] == DIR_SEPARATOR))
519 execpath[--n] = '\0';
520 switch (dirkind)
521 {
522 case GNUNET_OS_IPK_PREFIX:
523 case GNUNET_OS_IPK_SELF_PREFIX:
524 dirname = GNUNET_strdup (DIR_SEPARATOR_STR);
525 break;
526
527 case GNUNET_OS_IPK_BINDIR:
528 dirname = GNUNET_strdup (DIR_SEPARATOR_STR "bin" DIR_SEPARATOR_STR);
529 break;
530
531 case GNUNET_OS_IPK_LIBDIR:
532 if (isbasedir)
533 {
534 GNUNET_asprintf (&tmp,
535 "%s%s%s%s%s%s%s",
536 execpath,
537 DIR_SEPARATOR_STR "lib",
538 (NULL != multiarch) ? DIR_SEPARATOR_STR : "",
539 (NULL != multiarch) ? multiarch : "",
540 DIR_SEPARATOR_STR,
541 current_pd->project_dirname,
542 DIR_SEPARATOR_STR);
543 if (GNUNET_YES == GNUNET_DISK_directory_test (tmp, GNUNET_YES))
544 {
545 GNUNET_free (execpath);
546 return tmp;
547 }
548 GNUNET_free (tmp);
549 tmp = NULL;
550 dirname = NULL;
551 if (4 == sizeof(void *))
552 {
553 GNUNET_asprintf (&dirname,
554 DIR_SEPARATOR_STR "lib32" DIR_SEPARATOR_STR
555 "%s" DIR_SEPARATOR_STR,
556 current_pd->project_dirname);
557 GNUNET_asprintf (&tmp, "%s%s", execpath, dirname);
558 }
559 if (8 == sizeof(void *))
560 {
561 GNUNET_asprintf (&dirname,
562 DIR_SEPARATOR_STR "lib64" DIR_SEPARATOR_STR
563 "%s" DIR_SEPARATOR_STR,
564 current_pd->project_dirname);
565 GNUNET_asprintf (&tmp, "%s%s", execpath, dirname);
566 }
567
568 if ((NULL != tmp) &&
569 (GNUNET_YES == GNUNET_DISK_directory_test (tmp, GNUNET_YES)))
570 {
571 GNUNET_free (execpath);
572 GNUNET_free (dirname);
573 return tmp;
574 }
575 GNUNET_free (tmp);
576 GNUNET_free (dirname);
577 }
578 GNUNET_asprintf (&dirname,
579 DIR_SEPARATOR_STR "%s" DIR_SEPARATOR_STR,
580 current_pd->project_dirname);
581 break;
582
583 case GNUNET_OS_IPK_DATADIR:
584 GNUNET_asprintf (&dirname,
585 DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR
586 "%s" DIR_SEPARATOR_STR,
587 current_pd->project_dirname);
588 break;
589
590 case GNUNET_OS_IPK_LOCALEDIR:
591 dirname = GNUNET_strdup (DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR
592 "locale" DIR_SEPARATOR_STR);
593 break;
594
595 case GNUNET_OS_IPK_ICONDIR:
596 dirname = GNUNET_strdup (DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR
597 "icons" DIR_SEPARATOR_STR);
598 break;
599
600 case GNUNET_OS_IPK_DOCDIR:
601 GNUNET_asprintf (&dirname,
602 DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR
603 "doc" DIR_SEPARATOR_STR
604 "%s" DIR_SEPARATOR_STR,
605 current_pd->project_dirname);
606 break;
607
608 case GNUNET_OS_IPK_LIBEXECDIR:
609 if (isbasedir)
610 {
611 GNUNET_asprintf (&dirname,
612 DIR_SEPARATOR_STR "%s" DIR_SEPARATOR_STR
613 "libexec" DIR_SEPARATOR_STR,
614 current_pd->project_dirname);
615 GNUNET_asprintf (&tmp,
616 "%s%s%s%s",
617 execpath,
618 DIR_SEPARATOR_STR "lib" DIR_SEPARATOR_STR,
619 (NULL != multiarch) ? multiarch : "",
620 dirname);
621 GNUNET_free (dirname);
622 if (GNUNET_YES == GNUNET_DISK_directory_test (tmp, GNUNET_YES))
623 {
624 GNUNET_free (execpath);
625 return tmp;
626 }
627 GNUNET_free (tmp);
628 tmp = NULL;
629 dirname = NULL;
630 if (4 == sizeof(void *))
631 {
632 GNUNET_asprintf (&dirname,
633 DIR_SEPARATOR_STR "lib32" DIR_SEPARATOR_STR
634 "%s" DIR_SEPARATOR_STR
635 "libexec" DIR_SEPARATOR_STR,
636 current_pd->project_dirname);
637 GNUNET_asprintf (&tmp, "%s%s", execpath, dirname);
638 }
639 if (8 == sizeof(void *))
640 {
641 GNUNET_asprintf (&dirname,
642 DIR_SEPARATOR_STR "lib64" DIR_SEPARATOR_STR
643 "%s" DIR_SEPARATOR_STR
644 "libexec" DIR_SEPARATOR_STR,
645 current_pd->project_dirname);
646 GNUNET_asprintf (&tmp, "%s%s", execpath, dirname);
647 }
648 if ((NULL != tmp) &&
649 (GNUNET_YES == GNUNET_DISK_directory_test (tmp, GNUNET_YES)))
650 {
651 GNUNET_free (execpath);
652 GNUNET_free (dirname);
653 return tmp;
654 }
655 GNUNET_free (tmp);
656 GNUNET_free (dirname);
657 }
658 GNUNET_asprintf (&dirname,
659 DIR_SEPARATOR_STR "%s" DIR_SEPARATOR_STR
660 "libexec" DIR_SEPARATOR_STR,
661 current_pd->project_dirname);
662 break;
663
664 default:
665 GNUNET_free (execpath);
666 return NULL;
667 }
668 GNUNET_asprintf (&tmp, "%s%s", execpath, dirname);
669 GNUNET_free (dirname);
670 GNUNET_free (execpath);
671 return tmp;
672}
673
674
675/**
676 * Given the name of a gnunet-helper, gnunet-service or gnunet-daemon
677 * binary, try to prefix it with the libexec/-directory to get the
678 * full path.
679 *
680 * @param progname name of the binary
681 * @return full path to the binary, if possible, otherwise copy of 'progname'
682 */
683char *
684GNUNET_OS_get_libexec_binary_path (const char *progname)
685{
686 static char *cache;
687 char *libexecdir;
688 char *binary;
689
690 if ((DIR_SEPARATOR == progname[0]) ||
691 (GNUNET_YES ==
692 GNUNET_STRINGS_path_is_absolute (progname, GNUNET_NO, NULL, NULL)))
693 return GNUNET_strdup (progname);
694 if (NULL != cache)
695 libexecdir = cache;
696 else
697 libexecdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBEXECDIR);
698 if (NULL == libexecdir)
699 return GNUNET_strdup (progname);
700 GNUNET_asprintf (&binary, "%s%s", libexecdir, progname);
701 cache = libexecdir;
702 return binary;
703}
704
705
706/**
707 * Given the name of a helper, service or daemon binary construct the full
708 * path to the binary using the SUID_BINARY_PATH in the PATHS section of the
709 * configuration. If that option is not present, fall back to
710 * GNUNET_OS_get_libexec_binary_path. If @a progname is an absolute path, a
711 * copy of this path is returned.
712 *
713 * @param cfg configuration to inspect
714 * @param progname name of the binary
715 * @return full path to the binary, if possible, a copy of @a progname
716 * otherwise
717 */
718char *
719GNUNET_OS_get_suid_binary_path (const struct GNUNET_CONFIGURATION_Handle *cfg,
720 const char *progname)
721{
722 static char *cache;
723 char *binary = NULL;
724 char *path = NULL;
725 size_t path_len;
726
727 if (GNUNET_YES ==
728 GNUNET_STRINGS_path_is_absolute (progname, GNUNET_NO, NULL, NULL))
729 {
730 return GNUNET_strdup (progname);
731 }
732 if (NULL != cache)
733 path = cache;
734 else
735 GNUNET_CONFIGURATION_get_value_string (cfg,
736 "PATHS",
737 "SUID_BINARY_PATH",
738 &path);
739 if ((NULL == path) || (0 == strlen (path)))
740 {
741 if (NULL != path)
742 GNUNET_free (path);
743 cache = NULL;
744 return GNUNET_OS_get_libexec_binary_path (progname);
745 }
746 path_len = strlen (path);
747 GNUNET_asprintf (&binary,
748 "%s%s%s",
749 path,
750 (path[path_len - 1] == DIR_SEPARATOR) ? ""
751 : DIR_SEPARATOR_STR,
752 progname);
753 cache = path;
754 return binary;
755}
756
757
758enum GNUNET_GenericReturnValue
759GNUNET_OS_check_helper_binary (const char *binary,
760 bool check_suid,
761 const char *params)
762{
763 struct stat statbuf;
764 char *p;
765 char *pf;
766
767 if ((GNUNET_YES ==
768 GNUNET_STRINGS_path_is_absolute (binary, GNUNET_NO, NULL, NULL)) ||
769 (0 == strncmp (binary, "./", 2)))
770 {
771 p = GNUNET_strdup (binary);
772 }
773 else
774 {
775 p = get_path_from_PATH (binary);
776 if (NULL != p)
777 {
778 GNUNET_asprintf (&pf, "%s/%s", p, binary);
779 GNUNET_free (p);
780 p = pf;
781 }
782 }
783
784 if (NULL == p)
785 {
786 LOG (GNUNET_ERROR_TYPE_INFO,
787 _ ("Could not find binary `%s' in PATH!\n"),
788 binary);
789 return GNUNET_SYSERR;
790 }
791 if (0 != access (p, X_OK))
792 {
793 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", p);
794 GNUNET_free (p);
795 return GNUNET_SYSERR;
796 }
797
798 if (0 == getuid ())
799 {
800 /* as we run as root, we don't insist on SUID */
801 GNUNET_free (p);
802 return GNUNET_YES;
803 }
804
805 if (0 != stat (p, &statbuf))
806 {
807 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", p);
808 GNUNET_free (p);
809 return GNUNET_SYSERR;
810 }
811 if (check_suid)
812 {
813 (void) params;
814 if ((0 != (statbuf.st_mode & S_ISUID)) && (0 == statbuf.st_uid))
815 {
816 GNUNET_free (p);
817 return GNUNET_YES;
818 }
819 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
820 _ ("Binary `%s' exists, but is not SUID\n"),
821 p);
822 /* binary exists, but not SUID */
823 }
824 GNUNET_free (p);
825 return GNUNET_NO;
826}
827
828
829/* end of os_installation.c */