Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief Source for the getenv library
5 : *
6 : * \note there are two necessary bootstrap phases:
7 : *
8 : * 1.) bootstrapping in pre-main phase when no allocation is possible
9 : * 2.) bootstrapping when elektra modules use getenv()
10 : *
11 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
12 : *
13 : */
14 :
15 : #ifndef _GNU_SOURCE
16 : #define _GNU_SOURCE // for RTLD_NEXT (except BSDI)
17 : #endif
18 :
19 : #include <kdbconfig.h>
20 : #include <kdbgetenv.h>
21 : #include <kdbmacros.h>
22 :
23 : #include <kdbcontext.hpp>
24 :
25 : #include <kdbhelper.h>
26 :
27 : #include <dlfcn.h>
28 : #include <libgen.h>
29 : #include <signal.h>
30 : #include <stdio.h>
31 : #include <stdlib.h>
32 : #include <string.h>
33 : #include <sys/types.h> // euid
34 : #include <unistd.h> // euid
35 :
36 : #ifdef __powerpc__
37 : #include <elf.h>
38 : #include <link.h>
39 : #include <sys/auxv.h>
40 : #endif
41 :
42 : #include <chrono>
43 : #include <iostream>
44 : #include <sstream>
45 : #include <string>
46 :
47 : /* BSDI has this functionality, but its not defined */
48 : #if !defined(RTLD_NEXT)
49 : #define RTLD_NEXT ((void *) -1L)
50 : #endif
51 :
52 : using namespace std;
53 : using namespace ckdb;
54 :
55 : #define LOG \
56 : if (elektraLog) (*elektraLog)
57 :
58 : #define ELEKTRA_GETENV_USE_LOCKS 1
59 :
60 : #if ELEKTRA_GETENV_USE_LOCKS
61 : #if defined(__APPLE__) && defined(__MACH__)
62 : #define ELEKTRA_MUTEX_INIT PTHREAD_RECURSIVE_MUTEX_INITIALIZER
63 : #else
64 : #define ELEKTRA_MUTEX_INIT PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
65 : #endif
66 : #endif
67 :
68 : namespace ckdb
69 : {
70 :
71 : extern "C" {
72 : Key * elektraParentKey;
73 : KeySet * elektraConfig;
74 : KDB * elektraRepo;
75 : Key * elektraFallbackParentKey;
76 : KeySet * elektraFallbackConfig;
77 : KDB * elektraFallbackRepo;
78 :
79 : } // extern "C"
80 :
81 : namespace
82 : {
83 :
84 120 : class KeyValueLayer : public kdb::Layer
85 : {
86 : public:
87 210 : KeyValueLayer (std::string key, std::string value_) : m_key (std::move (key)), m_value (std::move (value_))
88 : {
89 70 : }
90 140 : std::string id () const override
91 : {
92 280 : return m_key;
93 : }
94 16 : std::string operator() () const override
95 : {
96 32 : return m_value;
97 : }
98 :
99 : private:
100 : std::string m_key;
101 : std::string m_value;
102 : };
103 :
104 24 : class GetEnvContext : public kdb::Context
105 : {
106 : public:
107 70 : void addLayer (std::string layername, std::string layervalue)
108 : {
109 280 : std::shared_ptr<kdb::Layer> layer = make_shared<KeyValueLayer> (layername, layervalue);
110 70 : activateLayer (layer);
111 70 : }
112 : void clearAllLayer ()
113 : {
114 0 : kdb::Context::clearAllLayer ();
115 : }
116 12 : } elektraEnvContext;
117 :
118 : #ifdef __powerpc__
119 : typedef int (*fcn) (int argc, char ** argv, char ** ev, ElfW (auxv_t) * auxvec, void (*rtld_fini) (void), void * stinfo,
120 : char ** stack_on_entry);
121 : #else
122 : typedef int (*fcn) (int *(main) (int, char **, char **), int argc, char ** argv, void (*init) (void), void (*fini) (void),
123 : void (*rtld_fini) (void), void(*stack_end));
124 : #endif
125 : typedef char * (*gfcn) (const char *);
126 :
127 : union Start
128 : {
129 : void * d;
130 : fcn f;
131 : } start; // symbol for libc pre-main
132 : union Sym
133 : {
134 : void * d;
135 : gfcn f;
136 : } sym, ssym; // symbols for libc (secure) getenv
137 :
138 : typedef pid_t (*ffcn) (void);
139 : union Fork
140 : {
141 : void * d;
142 : ffcn f;
143 : } ffork; // symbols for libc fork
144 :
145 : std::chrono::milliseconds elektraReloadTimeout;
146 : std::chrono::system_clock::time_point elektraReloadNext;
147 12 : std::shared_ptr<ostream> elektraLog;
148 : bool elektraInGetEnv;
149 12 : KeySet * elektraDocu = ksNew (20,
150 : #include "readme_elektrify-getenv.c"
151 : KS_END);
152 :
153 0 : int to_ (int c)
154 : {
155 0 : if (c == '-') return '_';
156 0 : return c;
157 : }
158 :
159 : pthread_mutex_t elektraGetEnvMutex = ELEKTRA_MUTEX_INIT;
160 :
161 :
162 : } // anonymous namespace
163 :
164 :
165 1240 : extern "C" void elektraLockMutex ()
166 : {
167 : #if ELEKTRA_GETENV_USE_LOCKS
168 1240 : pthread_mutex_lock (&elektraGetEnvMutex);
169 : #endif
170 1240 : }
171 :
172 1240 : extern "C" void elektraUnlockMutex ()
173 : {
174 : #if ELEKTRA_GETENV_USE_LOCKS
175 1240 : pthread_mutex_unlock (&elektraGetEnvMutex);
176 : #endif
177 1240 : }
178 :
179 :
180 0 : void printVersion ()
181 : {
182 0 : cout << "Elektra getenv is active" << std::endl;
183 0 : Key * k = keyNew ("system/elektra/version", KEY_END);
184 0 : KDB * kdb = kdbOpen (k);
185 0 : KeySet * c = ksNew (20, KS_END);
186 0 : kdbGet (kdb, c, k);
187 0 : kdbClose (kdb, k);
188 0 : keyDel (k);
189 0 : Key * kdb_version = ksLookupByName (c, "system/elektra/version/constants/KDB_VERSION", 0);
190 0 : if (!kdb_version)
191 : {
192 0 : cerr << "Could not lookup KDB_VERSION key" << endl;
193 : }
194 : else
195 : {
196 0 : cout << "KDB_VERSION: " << keyString (kdb_version) << endl;
197 : }
198 0 : cout << "KDB_GETENV_VERSION: " << KDB_GETENV_VERSION << endl;
199 0 : ksDel (c);
200 0 : }
201 :
202 4 : void addOverride (string kv)
203 : {
204 8 : stringstream ss (kv);
205 16 : string k, v;
206 4 : getline (ss, k, '=');
207 4 : getline (ss, v);
208 4 : LOG << "add override " << k << " with " << v << endl;
209 :
210 16 : string fullName = "proc/elektra/intercept/getenv/override/";
211 4 : fullName += k;
212 8 : ksAppendKey (elektraConfig, keyNew (fullName.c_str (), KEY_VALUE, v.c_str (), KEY_END));
213 4 : }
214 :
215 0 : void addOption (string kv)
216 : {
217 0 : std::transform (kv.begin (), kv.end (), kv.begin (), to_);
218 0 : stringstream ss (kv);
219 0 : string k, v;
220 0 : getline (ss, k, '=');
221 0 : getline (ss, v);
222 0 : LOG << "add option " << k << " with " << v << endl;
223 :
224 0 : string fullName = "proc/elektra/intercept/getenv/option/";
225 0 : fullName += k;
226 0 : ksAppendKey (elektraConfig, keyNew (fullName.c_str (), KEY_VALUE, v.c_str (), KEY_END));
227 0 : }
228 :
229 4 : void addLayer (string kv)
230 : {
231 8 : stringstream ss (kv);
232 16 : string k, v;
233 4 : getline (ss, k, '%');
234 4 : if (ss.get () != '=') return;
235 4 : getline (ss, v);
236 4 : LOG << "add layer " << k << " with " << v << endl;
237 :
238 16 : string fullName = "proc/elektra/intercept/getenv/layer/";
239 4 : fullName += k;
240 8 : ksAppendKey (elektraConfig, keyNew (fullName.c_str (), KEY_VALUE, v.c_str (), KEY_END));
241 : }
242 :
243 22 : void giveName (string name)
244 : {
245 22 : char * n = elektraStrDup (name.c_str ());
246 88 : std::string basename = ::basename (n);
247 22 : elektraFree (n);
248 22 : LOG << "give name " << name << ", basename: " << basename << std::endl;
249 22 : ksAppendKey (elektraConfig, keyNew ("proc/elektra/intercept/getenv/layer/name", KEY_VALUE, name.c_str (), KEY_END));
250 22 : ksAppendKey (elektraConfig, keyNew ("proc/elektra/intercept/getenv/layer/basename", KEY_VALUE, basename.c_str (), KEY_END));
251 22 : }
252 :
253 22 : void parseArgs (int * argc, char ** argv)
254 : {
255 88 : const string prefix = "--elektra";
256 22 : LOG << "Parsing args " << *argc << endl;
257 :
258 88 : giveName (argv[0]);
259 :
260 22 : int length = *argc;
261 54 : for (int i = 1; i < length; ++i)
262 : {
263 128 : std::string argument = argv[i];
264 32 : LOG << "Process argument " << argument << std::endl;
265 32 : if (argument.size () < prefix.size ())
266 : {
267 4 : LOG << "Skip argument " << argument << std::endl;
268 : }
269 56 : else if (argument.substr (0, prefix.size ()) == prefix)
270 : {
271 16 : string kv = argument.substr (prefix.size ());
272 8 : LOG << "Handling parameter: " << kv << endl;
273 :
274 8 : if (kv.empty ())
275 : ; // ignore but consume --elektra
276 8 : else if (kv[0] == '-')
277 : {
278 0 : addOption (kv.substr (1));
279 : }
280 8 : else if (kv[0] == ':')
281 : {
282 8 : addOverride (kv.substr (1));
283 : }
284 4 : else if (kv[0] == '%')
285 : {
286 8 : addLayer (kv.substr (1));
287 : }
288 : // ignore but consume all others
289 :
290 : // we consumed a parameter
291 8 : argv[i] = nullptr;
292 : }
293 : }
294 22 : char ** oldEnd = &argv[length];
295 44 : char ** newEnd = remove_if<char **> (argv, oldEnd, [](char * c) { return c == nullptr; });
296 22 : *newEnd = nullptr;
297 22 : const size_t toSubtract = oldEnd - newEnd;
298 22 : *argc -= toSubtract;
299 22 : }
300 :
301 0 : void addEnvironment (string kv)
302 : {
303 0 : std::transform (kv.begin (), kv.end (), kv.begin (), ::tolower);
304 0 : stringstream ss (kv);
305 0 : string k, v;
306 0 : getline (ss, k, '=');
307 0 : getline (ss, v);
308 0 : LOG << "add option " << k << " with " << v << endl;
309 :
310 0 : string fullName = "proc/elektra/intercept/getenv/option/";
311 0 : fullName += k;
312 0 : ksAppendKey (elektraConfig, keyNew (fullName.c_str (), KEY_VALUE, v.c_str (), KEY_END));
313 0 : }
314 :
315 : extern "C" {
316 : extern char ** environ;
317 : }
318 :
319 68 : void parseEnvironment ()
320 : {
321 272 : const string prefix = "ELEKTRA_";
322 : char ** env;
323 3808 : for (env = environ; *env != nullptr; env++)
324 : {
325 14960 : std::string argument = *env;
326 7480 : if (argument.substr (0, prefix.size ()) == prefix)
327 : {
328 0 : addEnvironment (argument.substr (prefix.size ()));
329 : }
330 : }
331 68 : }
332 :
333 168 : void addLayersHelper (KeySet * lookupConfig, string prefix)
334 : {
335 168 : ksRewind (elektraConfig);
336 : Key * c;
337 656 : while ((c = ksNext (elektraConfig)))
338 : {
339 976 : std::string fullName = keyName (c);
340 244 : size_t pos = fullName.find ('/');
341 488 : if (pos != string::npos && fullName.substr (pos, prefix.size ()) == prefix)
342 : {
343 140 : std::string cascadingName = fullName.substr (fullName.find ('/'));
344 70 : Key * found = ksLookupByName (lookupConfig, cascadingName.c_str (), 0);
345 140 : string name = fullName.substr (fullName.find ('/') + prefix.size ());
346 280 : string value = keyString (found);
347 70 : LOG << "Will add layer " << name << " with " << value << endl;
348 280 : elektraEnvContext.addLayer (name, value);
349 : }
350 : }
351 168 : }
352 :
353 84 : void addLayers ()
354 : {
355 : using namespace ckdb;
356 84 : KeySet * lookupConfig = ksDup (elektraConfig);
357 :
358 : // add fallback config
359 336 : addLayersHelper (lookupConfig, "/env/layer/");
360 : // override fallback config if new config is found
361 336 : addLayersHelper (lookupConfig, "/elektra/intercept/getenv/layer/");
362 :
363 84 : ksDel (lookupConfig);
364 84 : }
365 :
366 12 : void elektraSingleCleanup ()
367 : {
368 : // make everything really proper clean:
369 12 : ksDel (elektraDocu);
370 12 : elektraLog.reset ();
371 12 : }
372 :
373 :
374 : // always preffer new config path over old/fallback path
375 :
376 68 : void applyOptions ()
377 : {
378 68 : Key * k = nullptr;
379 :
380 68 : elektraLog.reset ();
381 204 : if (((k = ksLookupByName (elektraConfig, "/elektra/intercept/getenv/option/debug", 0)) ||
382 68 : (k = ksLookupByName (elektraConfig, "/env/option/debug", 0))) &&
383 0 : !keyIsBinary (k))
384 : {
385 0 : if (keyGetValueSize (k) > 1)
386 : {
387 0 : elektraLog = make_shared<ofstream> (keyString (k), fstream::app);
388 : }
389 : else
390 : {
391 0 : elektraLog = shared_ptr<ostream> (&cerr, [](ostream *) {});
392 : }
393 0 : LOG << "Elektra getenv starts logging to ";
394 0 : if (elektraLog.get () == &cerr)
395 : {
396 0 : LOG << "stderr";
397 : }
398 : else
399 : {
400 0 : LOG << keyString (k);
401 : }
402 0 : LOG << endl;
403 : }
404 :
405 204 : if (((k = ksLookupByName (elektraConfig, "/elektra/intercept/getenv/option/clearenv", 0)) ||
406 68 : (k = ksLookupByName (elektraConfig, "/env/option/clearenv", 0))) &&
407 0 : !keyIsBinary (k))
408 : {
409 0 : LOG << "clearing the environment" << endl;
410 : #ifdef HAVE_CLEARENV
411 0 : clearenv ();
412 : #else
413 : #warning Your system does not provide clearenv, this might be a security problem
414 : #endif
415 0 : environ = nullptr;
416 : }
417 :
418 68 : elektraReloadTimeout = std::chrono::milliseconds::zero ();
419 204 : if (((k = ksLookupByName (elektraConfig, "/elektra/intercept/getenv/option/reload_timeout", 0)) ||
420 68 : (k = ksLookupByName (elektraConfig, "/env/option/reload_timeout", 0))) &&
421 0 : !keyIsBinary (k))
422 : {
423 0 : LOG << "activate reloading feature" << endl;
424 :
425 : // we do not care about errors, 0 is an invalid number anyway
426 0 : std::chrono::milliseconds::rep v = atoi (keyString (k));
427 0 : elektraReloadTimeout = std::chrono::milliseconds (v);
428 : }
429 :
430 204 : if (((k = ksLookupByName (elektraConfig, "/elektra/intercept/getenv/option/help", 0)) ||
431 68 : (k = ksLookupByName (elektraConfig, "/env/option/help", 0))) &&
432 0 : !keyIsBinary (k))
433 : {
434 0 : cout << keyString (ksLookupByName (elektraDocu, "system/elektra/modules/elektrify-getenv/infos/description", 0)) << endl;
435 0 : exit (0);
436 : }
437 :
438 204 : if (((k = ksLookupByName (elektraConfig, "/elektra/intercept/getenv/option/version", 0)) ||
439 68 : (k = ksLookupByName (elektraConfig, "/env/option/version", 0))) &&
440 0 : !keyIsBinary (k))
441 : {
442 0 : printVersion ();
443 0 : exit (0);
444 : }
445 68 : }
446 :
447 68 : extern "C" void elektraOpen (int * argc, char ** argv)
448 : {
449 68 : elektraLockMutex ();
450 68 : if (elektraRepo) elektraClose (); // already opened
451 :
452 68 : LOG << "opening elektra" << endl;
453 :
454 68 : elektraParentKey = keyNew ("/elektra/intercept/getenv", KEY_END);
455 68 : elektraConfig = ksNew (20, KS_END);
456 68 : elektraRepo = kdbOpen (elektraParentKey);
457 68 : kdbGet (elektraRepo, elektraConfig, elektraParentKey);
458 :
459 68 : elektraFallbackParentKey = keyNew ("/env", KEY_END);
460 68 : elektraFallbackConfig = ksNew (20, KS_END);
461 68 : elektraFallbackRepo = kdbOpen (elektraFallbackParentKey);
462 68 : kdbGet (elektraFallbackRepo, elektraFallbackConfig, elektraFallbackParentKey);
463 68 : ksAppend (elektraConfig, elektraFallbackConfig);
464 :
465 68 : parseEnvironment ();
466 68 : if (argc && argv)
467 : {
468 22 : parseArgs (argc, argv);
469 : }
470 :
471 : // reopen everything (if wrong variable names were used before)
472 68 : kdbClose (elektraRepo, elektraParentKey);
473 68 : elektraRepo = kdbOpen (elektraParentKey);
474 272 : std::string name = keyName (elektraParentKey);
475 68 : kdbGet (elektraRepo, elektraConfig, elektraParentKey);
476 68 : addLayers ();
477 68 : applyOptions ();
478 68 : elektraUnlockMutex ();
479 68 : }
480 :
481 78 : extern "C" void elektraClose ()
482 : {
483 78 : elektraLockMutex ();
484 78 : if (elektraRepo)
485 : {
486 68 : kdbClose (elektraRepo, elektraParentKey);
487 68 : ksDel (elektraConfig);
488 68 : keyDel (elektraParentKey);
489 68 : elektraRepo = nullptr;
490 : }
491 78 : if (elektraFallbackRepo)
492 : {
493 68 : kdbClose (elektraFallbackRepo, elektraFallbackParentKey);
494 68 : ksDel (elektraFallbackConfig);
495 68 : keyDel (elektraFallbackParentKey);
496 68 : elektraFallbackRepo = nullptr;
497 : }
498 78 : elektraUnlockMutex ();
499 78 : }
500 :
501 : extern "C" int __real_main (int argc, char ** argv, char ** env);
502 :
503 : #ifdef __powerpc__
504 : extern "C" int __libc_start_main (int argc, char ** argv, char ** ev, ElfW (auxv_t) * auxvec, void (*rtld_fini) (void), void * stinfo,
505 : char ** stack_on_entry)
506 : #else
507 12 : extern "C" int __libc_start_main (int *(main) (int, char **, char **), int argc, char ** argv, void (*init) (void), void (*fini) (void),
508 : void (*rtld_fini) (void), void(*stack_end))
509 : #endif
510 : {
511 12 : elektraLockMutex (); // dlsym mutex
512 12 : LOG << "wrapping main" << endl;
513 12 : if (start.d)
514 : { // double wrapping situation, do not reopen, just forward to next __libc_start_main
515 0 : start.d = dlsym (RTLD_NEXT, "__libc_start_main");
516 0 : elektraUnlockMutex (); // dlsym mutex end
517 : #ifdef __powerpc__
518 : int ret = (*start.f) (argc, argv, ev, auxvec, rtld_fini, stinfo, stack_on_entry);
519 : #else
520 0 : int ret = (*start.f) (main, argc, argv, init, fini, rtld_fini, stack_end);
521 : #endif
522 0 : return ret;
523 : }
524 :
525 12 : start.d = dlsym (RTLD_NEXT, "__libc_start_main");
526 12 : sym.d = dlsym (RTLD_NEXT, "getenv");
527 12 : ssym.d = dlsym (RTLD_NEXT, "secure_getenv");
528 12 : ffork.d = dlsym (RTLD_NEXT, "fork");
529 :
530 12 : elektraOpen (&argc, argv);
531 12 : elektraUnlockMutex (); // dlsym mutex end
532 : #ifdef __powerpc__
533 : int ret = (*start.f) (argc, argv, ev, auxvec, rtld_fini, stinfo, stack_on_entry);
534 : #else
535 12 : int ret = (*start.f) (main, argc, argv, init, fini, rtld_fini, stack_end);
536 : #endif
537 0 : elektraClose ();
538 0 : return ret;
539 : }
540 :
541 16 : extern "C" pid_t fork ()
542 : {
543 16 : pid_t ret = ffork.f ();
544 16 : if (ret == 0)
545 : {
546 : // reinitialize mutex in new process
547 : // fixes deadlock in akonadictl
548 8 : elektraGetEnvMutex = ELEKTRA_MUTEX_INIT;
549 : }
550 16 : return ret;
551 : }
552 :
553 11394 : Key * elektraContextEvaluation (ELEKTRA_UNUSED KeySet * ks, ELEKTRA_UNUSED Key * key, Key * found, option_t option)
554 : {
555 11394 : if (found && !strncmp (keyName (found), "spec/", 5) && option == KDB_O_CALLBACK)
556 : {
557 20 : const Key * meta = keyGetMeta (found, "context");
558 20 : if (meta)
559 : {
560 80 : string contextName = elektraEnvContext.evaluate (keyString (meta));
561 20 : LOG << ", in context: " << contextName;
562 : // only consider context if key actually exists, otherwise continue searching
563 20 : Key * ret = ksLookupByName (ks, contextName.c_str (), 0);
564 40 : if (ret) return ret; // use context override!
565 : }
566 : else
567 : {
568 0 : LOG << ", NO context";
569 : }
570 : }
571 : return found;
572 : }
573 :
574 2334 : Key * elektraLookupWithContext (std::string name)
575 : {
576 2334 : Key * search = keyNew (name.c_str (), KEY_META, "callback", "", KEY_FUNC, elektraContextEvaluation, KEY_END);
577 2334 : Key * ret = ksLookup (elektraConfig, search, 0);
578 2334 : keyDel (search);
579 2334 : return ret;
580 : }
581 :
582 2312 : char * elektraGetEnvKey (std::string const & fullName, bool & finish)
583 : {
584 4624 : Key * key = elektraLookupWithContext (fullName);
585 2312 : if (key)
586 : {
587 24 : LOG << " found " << fullName << ": " << keyString (key) << endl;
588 24 : finish = true;
589 24 : if (keyIsBinary (key)) return nullptr;
590 24 : return const_cast<char *> (keyString (key));
591 : }
592 :
593 2288 : finish = false;
594 2288 : LOG << " tried " << fullName << ",";
595 : return nullptr;
596 : }
597 :
598 :
599 : /**
600 : * @brief Uses Elektra to get from environment.
601 : *
602 : * @param name to be looked up in the environment.
603 : *
604 : * @return the value found for that key
605 : * @see getenv
606 : * @see secure_getenv
607 : */
608 1082 : char * elektraGetEnv (const char * cname, gfcn origGetenv)
609 : {
610 1082 : LOG << "elektraGetEnv(" << cname << ")";
611 1082 : if (!elektraRepo)
612 : { // no open Repo (needed for bootstrapping, if inside kdbOpen() getenv is used)
613 252 : char * ret = (*origGetenv) (cname);
614 252 : if (!ret)
615 : {
616 48 : LOG << " orig getenv returned null pointer" << endl;
617 : }
618 : else
619 204 : LOG << " orig getenv returned (" << strlen (ret) << ") <" << ret << ">" << endl;
620 : return ret;
621 : }
622 :
623 : // is reload feature enabled at all?
624 1660 : if (elektraReloadTimeout > std::chrono::milliseconds::zero ())
625 : {
626 0 : std::chrono::system_clock::time_point const now = std::chrono::system_clock::now ();
627 :
628 : // are we now ready to reload?
629 0 : if (now >= elektraReloadNext)
630 : {
631 0 : int ret = kdbGet (elektraRepo, elektraConfig, elektraParentKey);
632 :
633 : // was there a change?
634 0 : if (ret == 1)
635 : {
636 0 : elektraEnvContext.clearAllLayer ();
637 0 : addLayers ();
638 0 : applyOptions ();
639 : }
640 : }
641 :
642 0 : elektraReloadNext = now + elektraReloadTimeout;
643 : }
644 :
645 2490 : std::string name = cname;
646 830 : bool finish = false;
647 830 : char * ret = nullptr;
648 1660 : ret = elektraGetEnvKey ("/elektra/intercept/getenv/override/" + name, finish);
649 1644 : if (!ret) ret = elektraGetEnvKey ("/env/override/" + name, finish);
650 830 : if (finish) return ret;
651 :
652 806 : ret = (*origGetenv) (name.c_str ());
653 806 : if (ret)
654 : {
655 472 : LOG << " environ returned (" << strlen (ret) << ") <" << ret << ">" << endl;
656 : return ret;
657 : }
658 : else
659 334 : LOG << " tried environ,";
660 :
661 668 : ret = elektraGetEnvKey ("/elektra/intercept/getenv/fallback/" + name, finish);
662 668 : if (!ret) ret = elektraGetEnvKey ("/env/fallback/" + name, finish);
663 334 : if (finish) return ret;
664 :
665 334 : LOG << " nothing found" << endl;
666 : return nullptr;
667 : }
668 :
669 : /*
670 : // Nice trick to find next execution of elektraMalloc
671 : // set foo to (int*)-1 to trigger it
672 : int *foo = 0;
673 : extern "C" void* elektraMalloc (size_t size)
674 : {
675 : // LOG << "elektraMalloc " << size << endl;
676 : if (foo) printf("%d\n", *foo);
677 : return malloc(size);
678 : }
679 : */
680 :
681 : /**
682 : * @brief Search in environ, should be identical to getenv
683 : *
684 : * implementation is needed for bootstrapping in pre-main phases
685 : * where memory allocation hangs or crashes and thus dlsym cannot be used!
686 : *
687 : * @see getenv()
688 : */
689 0 : char * elektraBootstrapGetEnv (const char * name)
690 : {
691 0 : int len = strlen (name);
692 0 : if (environ == nullptr || len == 0)
693 : {
694 : return nullptr;
695 : }
696 :
697 : char ** env;
698 0 : for (env = environ; *env != nullptr; env++)
699 : {
700 0 : if (!strncmp (*env, name, len))
701 : {
702 0 : if ((*env)[len] == '=')
703 : {
704 0 : return &((*env)[len + 1]);
705 : }
706 : }
707 : }
708 :
709 : return nullptr;
710 : }
711 :
712 0 : char * elektraBootstrapSecureGetEnv (const char * name)
713 : {
714 0 : return (geteuid () != getuid () || getegid () != getgid ()) ? nullptr : elektraBootstrapGetEnv (name);
715 : }
716 :
717 1082 : extern "C" char * getenv (const char * name) // throw ()
718 : {
719 1082 : elektraLockMutex ();
720 1082 : if (!sym.f || elektraInGetEnv)
721 : {
722 0 : char * ret = elektraBootstrapGetEnv (name);
723 0 : elektraUnlockMutex ();
724 0 : return ret;
725 : }
726 :
727 1082 : elektraInGetEnv = true;
728 1082 : char * ret = elektraGetEnv (name, sym.f);
729 1082 : elektraInGetEnv = false;
730 1082 : elektraUnlockMutex ();
731 1082 : return ret;
732 : }
733 :
734 0 : extern "C" char * secure_getenv (const char * name) // throw ()
735 : {
736 0 : elektraLockMutex ();
737 0 : if (!ssym.f || elektraInGetEnv)
738 : {
739 0 : char * ret = elektraBootstrapSecureGetEnv (name);
740 0 : elektraUnlockMutex ();
741 0 : return ret;
742 : }
743 :
744 0 : elektraInGetEnv = true;
745 0 : char * ret = elektraGetEnv (name, ssym.f);
746 0 : elektraInGetEnv = false;
747 0 : elektraUnlockMutex ();
748 0 : return ret;
749 : }
750 36 : } // namespace ckdb
|