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 /*
7 ** File:        env.c
8 ** Description: Testing environment variable operations
9 **
10 */
11 #include "prenv.h"
12 #include "prmem.h"
13 #include "plgetopt.h"
14 
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 
19 PRIntn  debug = 0;
20 PRIntn  verbose = 0;
21 PRIntn  secure = 0;
22 PRBool  failedAlready = PR_FALSE;
23 
24 #define  ENVNAME    "NSPR_ENVIRONMENT_TEST_VARIABLE"
25 #define  ENVVALUE   "The expected result"
26 #define  ENVBUFSIZE 256
27 
28 char    *envBuf; /* buffer pointer. We leak memory here on purpose! */
29 
NewBuffer(size_t size)30 static char * NewBuffer( size_t size )
31 {
32     char *buf = malloc( size );
33     if ( NULL == buf ) {
34         printf("env: NewBuffer() failed\n");
35         exit(1);
36     }
37     return(buf);
38 } /* end NewBuffer() */
39 
main(int argc,char ** argv)40 int main(int argc, char **argv)
41 {
42     char    *value;
43     PRStatus    rc;
44 
45     {   /* Get command line options */
46         PLOptStatus os;
47         PLOptState *opt = PL_CreateOptState(argc, argv, "vds");
48 
49 	    while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
50         {
51 		    if (PL_OPT_BAD == os) continue;
52             switch (opt->option)
53             {
54             case 'd':  /* debug */
55                 debug = 1;
56                 break;
57             case 'v':  /* verbose */
58                 verbose = 1;
59                 break;
60             case 's':  /* secure / set[ug]id */
61                 /*
62                 ** To test PR_GetEnvSecure, make this executable (or a
63                 ** copy of it) setuid / setgid / otherwise inherently
64                 ** privileged (e.g., file capabilities) and run it
65                 ** with this flag.
66                 */
67                 secure = 1;
68                 break;
69              default:
70                 break;
71             }
72         }
73 	    PL_DestroyOptState(opt);
74     } /* end block "Get command line options" */
75 
76 #if 0
77     {
78         /*
79         ** This uses Windows native environment manipulation
80         ** as an experiment. Note the separation of namespace!
81         */
82         BOOL rv;
83         DWORD   size;
84         rv = SetEnvironmentVariable( ENVNAME, ENVVALUE );
85         if ( rv == 0 )  {
86             if (debug) printf("env: Shit! SetEnvironmentVariable() failed\n");
87             failedAlready = PR_TRUE;
88         }
89         if (verbose) printf("env: SetEnvironmentVariable() worked\n");
90 
91         size = GetEnvironmentVariable( ENVNAME, envBuf, ENVBUFSIZE );
92         if ( size == 0 )  {
93             if (debug) printf("env: Shit! GetEnvironmentVariable() failed. Found: %s\n", envBuf );
94             failedAlready = PR_TRUE;
95         }
96         if (verbose) printf("env: GetEnvironmentVariable() worked. Found: %s\n", envBuf);
97 
98         value = PR_GetEnv( ENVNAME );
99         if ( (NULL == value ) || (strcmp( value, ENVVALUE)))  {
100             if (debug) printf( "env: PR_GetEnv() failed retrieving WinNative. Found: %s\n", value);
101             failedAlready = PR_TRUE;
102         }
103         if (verbose) printf("env: PR_GetEnv() worked. Found: %s\n", value);
104     }
105 #endif
106 
107     /* set an environment variable, read it back */
108     envBuf = NewBuffer( ENVBUFSIZE );
109     sprintf( envBuf, ENVNAME "=" ENVVALUE );
110     rc = PR_SetEnv( envBuf );
111     if ( PR_FAILURE == rc )  {
112         if (debug) printf( "env: PR_SetEnv() failed setting\n");
113         failedAlready = PR_TRUE;
114     } else {
115         if (verbose) printf("env: PR_SetEnv() worked.\n");
116     }
117 
118     value = PR_GetEnv( ENVNAME );
119     if ( (NULL == value ) || (strcmp( value, ENVVALUE)))  {
120         if (debug) printf( "env: PR_GetEnv() Failed after setting\n" );
121         failedAlready = PR_TRUE;
122     } else {
123         if (verbose) printf("env: PR_GetEnv() worked after setting it. Found: %s\n", value );
124     }
125 
126     if ( secure ) {
127         /*
128         ** In this case we've been run with elevated privileges, so
129         ** test that PR_GetEnvSecure *doesn't* find that env var.
130         */
131         value = PR_GetEnvSecure( ENVNAME );
132         if ( NULL != value ) {
133             if (debug) printf( "env: PR_GetEnvSecure() failed; expected NULL, found \"%s\"\n", value );
134             failedAlready = PR_TRUE;
135         } else {
136             if (verbose) printf("env: PR_GetEnvSecure() worked\n" );
137         }
138     } else {
139         /*
140         ** In this case the program is being run normally, so do the
141         ** same check for PR_GetEnvSecure as for PR_GetEnv.
142         */
143         value = PR_GetEnvSecure( ENVNAME );
144         if ( (NULL == value ) || (strcmp( value, ENVVALUE)))  {
145             if (debug) printf( "env: PR_GetEnvSecure() Failed after setting\n" );
146             failedAlready = PR_TRUE;
147         } else {
148             if (verbose) printf("env: PR_GetEnvSecure() worked after setting it. Found: %s\n", value );
149         }
150     }
151 
152 /* ---------------------------------------------------------------------- */
153     /* check that PR_DuplicateEnvironment() agrees with PR_GetEnv() */
154     {
155 #if defined(XP_UNIX) && (!defined(DARWIN) || defined(HAVE_CRT_EXTERNS_H))
156         static const PRBool expect_failure = PR_FALSE;
157 #else
158         static const PRBool expect_failure = PR_TRUE;
159 #endif
160         char **i, **dupenv = PR_DuplicateEnvironment();
161 
162 
163         if ( NULL == dupenv ) {
164             if (expect_failure) {
165                 if (verbose) printf("env: PR_DuplicateEnvironment failed, "
166                                     "as expected on this platform.\n");
167             } else {
168                 if (debug) printf("env: PR_DuplicateEnvironment() failed.\n");
169                 failedAlready = PR_TRUE;
170             }
171         } else {
172             unsigned found = 0;
173 
174             if (expect_failure) {
175                 if (debug) printf("env: PR_DuplicateEnvironment() succeeded, "
176                                   "but failure is expected on this platform.\n");
177                 failedAlready = PR_TRUE;
178             } else {
179                 if (verbose) printf("env: PR_DuplicateEnvironment() succeeded.\n");
180             }
181             for (i = dupenv; *i; i++) {
182                 char *equals = strchr(*i, '=');
183 
184                 if ( equals == NULL ) {
185                     if (debug) printf("env: PR_DuplicateEnvironment() returned a string"
186                                       " with no '=': %s\n", *i);
187                     failedAlready = PR_TRUE;
188                 } else {
189                     /* We own this string, so we can temporarily alter it */
190                     /* *i is the null-terminated name; equals + 1 is the value */
191                     *equals = '\0';
192 
193                     if ( strcmp(*i, ENVNAME) == 0) {
194                         found++;
195                         if (verbose) printf("env: PR_DuplicateEnvironment() found " ENVNAME
196                                             " (%u so far).\n", found);
197                     }
198 
199                     /* Multiple values for the same name can't happen, according to POSIX. */
200                     value = PR_GetEnv(*i);
201                     if ( value == NULL ) {
202                         if (debug) printf("env: PR_DuplicateEnvironment() returned a name"
203                                           " which PR_GetEnv() failed to find: %s\n", *i);
204                         failedAlready = PR_TRUE;
205                     } else if ( strcmp(equals + 1, value) != 0) {
206                         if (debug) printf("env: PR_DuplicateEnvironment() returned the wrong"
207                                           " value for %s: expected %s; found %s\n",
208                                           *i, value, equals + 1);
209                         failedAlready = PR_TRUE;
210                     } else {
211                         if (verbose) printf("env: PR_DuplicateEnvironment() agreed with"
212                                             " PR_GetEnv() about %s\n", *i);
213                     }
214                 }
215                 PR_Free(*i);
216             }
217             PR_Free(dupenv);
218 
219             if (found != 1) {
220                 if (debug) printf("env: PR_DuplicateEnvironment() found %u entries for " ENVNAME
221                                   " (expected 1)\n", found);
222                 failedAlready = PR_TRUE;
223             } else {
224                 if (verbose) printf("env: PR_DuplicateEnvironment() found 1 entry for " ENVNAME "\n");
225             }
226         }
227     }
228 
229 /* ---------------------------------------------------------------------- */
230     /* un-set the variable, using RAW name... should not work */
231     envBuf = NewBuffer( ENVBUFSIZE );
232     sprintf( envBuf, ENVNAME );
233     rc = PR_SetEnv( envBuf );
234     if ( PR_FAILURE == rc )  {
235         if (verbose) printf( "env: PR_SetEnv() not un-set using RAW name. Good!\n");
236     } else {
237         if (debug) printf("env: PR_SetEnv() un-set using RAW name. Bad!\n" );
238         failedAlready = PR_TRUE;
239     }
240 
241     value = PR_GetEnv( ENVNAME );
242     if ( NULL == value ) {
243         if (debug) printf("env: PR_GetEnv() after un-set using RAW name. Bad!\n" );
244         failedAlready = PR_TRUE;
245     } else {
246         if (verbose) printf( "env: PR_GetEnv() after RAW un-set found: %s\n", value );
247     }
248 
249 /* ---------------------------------------------------------------------- */
250     /* set it again ... */
251     envBuf = NewBuffer( ENVBUFSIZE );
252     sprintf( envBuf, ENVNAME "=" ENVVALUE );
253     rc = PR_SetEnv( envBuf );
254     if ( PR_FAILURE == rc )  {
255         if (debug) printf( "env: PR_SetEnv() failed setting the second time.\n");
256         failedAlready = PR_TRUE;
257     } else {
258         if (verbose) printf("env: PR_SetEnv() worked.\n");
259     }
260 
261     /* un-set the variable using the form name= */
262     envBuf = NewBuffer( ENVBUFSIZE );
263     sprintf( envBuf, ENVNAME "=" );
264     rc = PR_SetEnv( envBuf );
265     if ( PR_FAILURE == rc )  {
266         if (debug) printf( "env: PR_SetEnv() failed un-setting using name=\n");
267         failedAlready = PR_TRUE;
268     } else {
269         if (verbose) printf("env: PR_SetEnv() un-set using name= worked\n" );
270     }
271 
272     value = PR_GetEnv( ENVNAME );
273     if (( NULL == value ) || ( 0x00 == *value )) {
274         if (verbose) printf("env: PR_GetEnv() after un-set using name= worked\n" );
275     } else {
276         if (debug) printf( "env: PR_GetEnv() after un-set using name=. Found: %s\n", value );
277         failedAlready = PR_TRUE;
278     }
279 /* ---------------------------------------------------------------------- */
280     /* un-set the variable using the form name= */
281     envBuf = NewBuffer( ENVBUFSIZE );
282     sprintf( envBuf, ENVNAME "999=" );
283     rc = PR_SetEnv( envBuf );
284     if ( PR_FAILURE == rc )  {
285         if (debug) printf( "env: PR_SetEnv() failed un-setting using name=\n");
286         failedAlready = PR_TRUE;
287     } else {
288         if (verbose) printf("env: PR_SetEnv() un-set using name= worked\n" );
289     }
290 
291     value = PR_GetEnv( ENVNAME "999" );
292     if (( NULL == value ) || ( 0x00 == *value )) {
293         if (verbose) printf("env: PR_GetEnv() after un-set using name= worked\n" );
294     } else {
295         if (debug) printf( "env: PR_GetEnv() after un-set using name=. Found: %s\n", value );
296         failedAlready = PR_TRUE;
297     }
298 
299 /* ---------------------------------------------------------------------- */
300     if (debug || verbose) printf("\n%s\n", (failedAlready)? "FAILED" : "PASSED" );
301     return( (failedAlready)? 1 : 0 );
302 }  /* main() */
303 
304 /* env.c */
305