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