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