1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include <string.h>
7 #include <stdlib.h>
8 #include "primpl.h"
9 #include "prmem.h"
10 
11 #if defined(XP_UNIX)
12 #include <unistd.h>
13 #if defined(DARWIN)
14 #if defined(HAVE_CRT_EXTERNS_H)
15 #include <crt_externs.h>
16 #endif /* HAVE_CRT_EXTERNS_H */
17 #else  /* DARWIN */
18 PR_IMPORT_DATA(char **) environ;
19 #endif /* DARWIN */
20 #endif /* XP_UNIX */
21 
22 #if !defined(HAVE_SECURE_GETENV) && defined(HAVE___SECURE_GETENV)
23 #define secure_getenv __secure_getenv
24 #define HAVE_SECURE_GETENV 1
25 #endif
26 
27 /* Lock used to lock the environment */
28 #if defined(_PR_NO_PREEMPT)
29 #define _PR_NEW_LOCK_ENV()
30 #define _PR_DELETE_LOCK_ENV()
31 #define _PR_LOCK_ENV()
32 #define _PR_UNLOCK_ENV()
33 #elif defined(_PR_LOCAL_THREADS_ONLY)
34 extern _PRCPU * _pr_primordialCPU;
35 static PRIntn _is;
36 #define _PR_NEW_LOCK_ENV()
37 #define _PR_DELETE_LOCK_ENV()
38 #define _PR_LOCK_ENV() if (_pr_primordialCPU) _PR_INTSOFF(_is);
39 #define _PR_UNLOCK_ENV() if (_pr_primordialCPU) _PR_INTSON(_is);
40 #else
41 static PRLock *_pr_envLock = NULL;
42 #define _PR_NEW_LOCK_ENV() {_pr_envLock = PR_NewLock();}
43 #define _PR_DELETE_LOCK_ENV() \
44     { if (_pr_envLock) { PR_DestroyLock(_pr_envLock); _pr_envLock = NULL; } }
45 #define _PR_LOCK_ENV() { if (_pr_envLock) PR_Lock(_pr_envLock); }
46 #define _PR_UNLOCK_ENV() { if (_pr_envLock) PR_Unlock(_pr_envLock); }
47 #endif
48 
49 /************************************************************************/
50 
_PR_InitEnv(void)51 void _PR_InitEnv(void)
52 {
53     _PR_NEW_LOCK_ENV();
54 }
55 
_PR_CleanupEnv(void)56 void _PR_CleanupEnv(void)
57 {
58     _PR_DELETE_LOCK_ENV();
59 }
60 
PR_GetEnv(const char * var)61 PR_IMPLEMENT(char*) PR_GetEnv(const char *var)
62 {
63     char *ev;
64 
65     if (!_pr_initialized) {
66         _PR_ImplicitInitialization();
67     }
68 
69     _PR_LOCK_ENV();
70     ev = _PR_MD_GET_ENV(var);
71     _PR_UNLOCK_ENV();
72     return ev;
73 }
74 
PR_GetEnvSecure(const char * var)75 PR_IMPLEMENT(char*) PR_GetEnvSecure(const char *var)
76 {
77 #ifdef HAVE_SECURE_GETENV
78     char *ev;
79 
80     if (!_pr_initialized) {
81         _PR_ImplicitInitialization();
82     }
83 
84     _PR_LOCK_ENV();
85     ev = secure_getenv(var);
86     _PR_UNLOCK_ENV();
87 
88     return ev;
89 #else
90 #ifdef XP_UNIX
91     /*
92     ** Fall back to checking uids and gids.  This won't detect any other
93     ** privilege-granting mechanisms the platform may have.  This also
94     ** can't detect the case where the process already called
95     ** setuid(geteuid()) and/or setgid(getegid()).
96     */
97     if (getuid() != geteuid() || getgid() != getegid()) {
98         return NULL;
99     }
100 #endif /* XP_UNIX */
101     return PR_GetEnv(var);
102 #endif /* HAVE_SECURE_GETENV */
103 }
104 
PR_SetEnv(const char * string)105 PR_IMPLEMENT(PRStatus) PR_SetEnv(const char *string)
106 {
107     PRIntn result;
108 
109     if (!_pr_initialized) {
110         _PR_ImplicitInitialization();
111     }
112 
113     if (!strchr(string, '=')) {
114         return(PR_FAILURE);
115     }
116 
117     _PR_LOCK_ENV();
118     result = _PR_MD_PUT_ENV((char*)string);
119     _PR_UNLOCK_ENV();
120     return result ? PR_FAILURE : PR_SUCCESS;
121 }
122 
123 #if defined(XP_UNIX) && (!defined(DARWIN) || defined(HAVE_CRT_EXTERNS_H))
PR_DuplicateEnvironment(void)124 PR_IMPLEMENT(char **) PR_DuplicateEnvironment(void)
125 {
126     char **the_environ, **result, **end, **src, **dst;
127 
128     _PR_LOCK_ENV();
129 #ifdef DARWIN
130     the_environ = *(_NSGetEnviron());
131 #else
132     the_environ = environ;
133 #endif
134 
135     for (end = the_environ; *end != NULL; end++)
136         /* empty loop body */;
137 
138     result = (char **)PR_Malloc(sizeof(char *) * (end - the_environ + 1));
139     if (result != NULL) {
140         for (src = the_environ, dst = result; src != end; src++, dst++) {
141             size_t len;
142 
143             len = strlen(*src) + 1;
144             *dst = PR_Malloc(len);
145             if (*dst == NULL) {
146                 /* Allocation failed.  Must clean up the half-copied env. */
147                 char **to_delete;
148 
149                 for (to_delete = result; to_delete != dst; to_delete++) {
150                     PR_Free(*to_delete);
151                 }
152                 PR_Free(result);
153                 result = NULL;
154                 goto out;
155             }
156             memcpy(*dst, *src, len);
157         }
158         *dst = NULL;
159     }
160 out:
161     _PR_UNLOCK_ENV();
162     return result;
163 }
164 #else
165 /* This platform doesn't support raw access to the environ block. */
PR_DuplicateEnvironment(void)166 PR_IMPLEMENT(char **) PR_DuplicateEnvironment(void)
167 {
168     return NULL;
169 }
170 #endif
171