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) {
52                 continue;
53             }
54             switch (opt->option)
55             {
56                 case 'd':  /* debug */
57                     debug = 1;
58                     break;
59                 case 'v':  /* verbose */
60                     verbose = 1;
61                     break;
62                 case 's':  /* secure / set[ug]id */
63                     /*
64                     ** To test PR_GetEnvSecure, make this executable (or a
65                     ** copy of it) setuid / setgid / otherwise inherently
66                     ** privileged (e.g., file capabilities) and run it
67                     ** with this flag.
68                     */
69                     secure = 1;
70                     break;
71                 default:
72                     break;
73             }
74         }
75         PL_DestroyOptState(opt);
76     } /* end block "Get command line options" */
77 
78 #if 0
79     {
80         /*
81         ** This uses Windows native environment manipulation
82         ** as an experiment. Note the separation of namespace!
83         */
84         BOOL rv;
85         DWORD   size;
86         rv = SetEnvironmentVariable( ENVNAME, ENVVALUE );
87         if ( rv == 0 )  {
88             if (debug) {
89                 printf("env: Shit! SetEnvironmentVariable() failed\n");
90             }
91             failedAlready = PR_TRUE;
92         }
93         if (verbose) {
94             printf("env: SetEnvironmentVariable() worked\n");
95         }
96 
97         size = GetEnvironmentVariable( ENVNAME, envBuf, ENVBUFSIZE );
98         if ( size == 0 )  {
99             if (debug) {
100                 printf("env: Shit! GetEnvironmentVariable() failed. Found: %s\n", envBuf );
101             }
102             failedAlready = PR_TRUE;
103         }
104         if (verbose) {
105             printf("env: GetEnvironmentVariable() worked. Found: %s\n", envBuf);
106         }
107 
108         value = PR_GetEnv( ENVNAME );
109         if ( (NULL == value ) || (strcmp( value, ENVVALUE)))  {
110             if (debug) {
111                 printf( "env: PR_GetEnv() failed retrieving WinNative. Found: %s\n", value);
112             }
113             failedAlready = PR_TRUE;
114         }
115         if (verbose) {
116             printf("env: PR_GetEnv() worked. Found: %s\n", value);
117         }
118     }
119 #endif
120 
121     /* set an environment variable, read it back */
122     envBuf = NewBuffer( ENVBUFSIZE );
123     sprintf( envBuf, ENVNAME "=" ENVVALUE );
124     rc = PR_SetEnv( envBuf );
125     if ( PR_FAILURE == rc )  {
126         if (debug) {
127             printf( "env: PR_SetEnv() failed setting\n");
128         }
129         failedAlready = PR_TRUE;
130     } else {
131         if (verbose) {
132             printf("env: PR_SetEnv() worked.\n");
133         }
134     }
135 
136     value = PR_GetEnv( ENVNAME );
137     if ( (NULL == value ) || (strcmp( value, ENVVALUE)))  {
138         if (debug) {
139             printf( "env: PR_GetEnv() Failed after setting\n" );
140         }
141         failedAlready = PR_TRUE;
142     } else {
143         if (verbose) {
144             printf("env: PR_GetEnv() worked after setting it. Found: %s\n", value );
145         }
146     }
147 
148     if ( secure ) {
149         /*
150         ** In this case we've been run with elevated privileges, so
151         ** test that PR_GetEnvSecure *doesn't* find that env var.
152         */
153         value = PR_GetEnvSecure( ENVNAME );
154         if ( NULL != value ) {
155             if (debug) {
156                 printf( "env: PR_GetEnvSecure() failed; expected NULL, found \"%s\"\n", value );
157             }
158             failedAlready = PR_TRUE;
159         } else {
160             if (verbose) {
161                 printf("env: PR_GetEnvSecure() worked\n" );
162             }
163         }
164     } else {
165         /*
166         ** In this case the program is being run normally, so do the
167         ** same check for PR_GetEnvSecure as for PR_GetEnv.
168         */
169         value = PR_GetEnvSecure( ENVNAME );
170         if ( (NULL == value ) || (strcmp( value, ENVVALUE)))  {
171             if (debug) {
172                 printf( "env: PR_GetEnvSecure() Failed after setting\n" );
173             }
174             failedAlready = PR_TRUE;
175         } else {
176             if (verbose) {
177                 printf("env: PR_GetEnvSecure() worked after setting it. Found: %s\n", value );
178             }
179         }
180     }
181 
182     /* ---------------------------------------------------------------------- */
183     /* check that PR_DuplicateEnvironment() agrees with PR_GetEnv() */
184     {
185 #if defined(XP_UNIX) && (!defined(DARWIN) || defined(HAVE_CRT_EXTERNS_H))
186         static const PRBool expect_failure = PR_FALSE;
187 #else
188         static const PRBool expect_failure = PR_TRUE;
189 #endif
190         char **i, **dupenv = PR_DuplicateEnvironment();
191 
192 
193         if ( NULL == dupenv ) {
194             if (expect_failure) {
195                 if (verbose) printf("env: PR_DuplicateEnvironment failed, "
196                                         "as expected on this platform.\n");
197             } else {
198                 if (debug) {
199                     printf("env: PR_DuplicateEnvironment() failed.\n");
200                 }
201                 failedAlready = PR_TRUE;
202             }
203         } else {
204             unsigned found = 0;
205 
206             if (expect_failure) {
207                 if (debug) printf("env: PR_DuplicateEnvironment() succeeded, "
208                                       "but failure is expected on this platform.\n");
209                 failedAlready = PR_TRUE;
210             } else {
211                 if (verbose) {
212                     printf("env: PR_DuplicateEnvironment() succeeded.\n");
213                 }
214             }
215             for (i = dupenv; *i; i++) {
216                 char *equals = strchr(*i, '=');
217 
218                 if ( equals == NULL ) {
219                     if (debug) printf("env: PR_DuplicateEnvironment() returned a string"
220                                           " with no '=': %s\n", *i);
221                     failedAlready = PR_TRUE;
222                 } else {
223                     /* We own this string, so we can temporarily alter it */
224                     /* *i is the null-terminated name; equals + 1 is the value */
225                     *equals = '\0';
226 
227                     if ( strcmp(*i, ENVNAME) == 0) {
228                         found++;
229                         if (verbose) printf("env: PR_DuplicateEnvironment() found " ENVNAME
230                                                 " (%u so far).\n", found);
231                     }
232 
233                     /* Multiple values for the same name can't happen, according to POSIX. */
234                     value = PR_GetEnv(*i);
235                     if ( value == NULL ) {
236                         if (debug) printf("env: PR_DuplicateEnvironment() returned a name"
237                                               " which PR_GetEnv() failed to find: %s\n", *i);
238                         failedAlready = PR_TRUE;
239                     } else if ( strcmp(equals + 1, value) != 0) {
240                         if (debug) printf("env: PR_DuplicateEnvironment() returned the wrong"
241                                               " value for %s: expected %s; found %s\n",
242                                               *i, value, equals + 1);
243                         failedAlready = PR_TRUE;
244                     } else {
245                         if (verbose) printf("env: PR_DuplicateEnvironment() agreed with"
246                                                 " PR_GetEnv() about %s\n", *i);
247                     }
248                 }
249                 PR_Free(*i);
250             }
251             PR_Free(dupenv);
252 
253             if (found != 1) {
254                 if (debug) printf("env: PR_DuplicateEnvironment() found %u entries for " ENVNAME
255                                       " (expected 1)\n", found);
256                 failedAlready = PR_TRUE;
257             } else {
258                 if (verbose) {
259                     printf("env: PR_DuplicateEnvironment() found 1 entry for " ENVNAME "\n");
260                 }
261             }
262         }
263     }
264 
265     /* ---------------------------------------------------------------------- */
266     /* un-set the variable, using RAW name... should not work */
267     envBuf = NewBuffer( ENVBUFSIZE );
268     sprintf( envBuf, ENVNAME );
269     rc = PR_SetEnv( envBuf );
270     if ( PR_FAILURE == rc )  {
271         if (verbose) {
272             printf( "env: PR_SetEnv() not un-set using RAW name. Good!\n");
273         }
274     } else {
275         if (debug) {
276             printf("env: PR_SetEnv() un-set using RAW name. Bad!\n" );
277         }
278         failedAlready = PR_TRUE;
279     }
280 
281     value = PR_GetEnv( ENVNAME );
282     if ( NULL == value ) {
283         if (debug) {
284             printf("env: PR_GetEnv() after un-set using RAW name. Bad!\n" );
285         }
286         failedAlready = PR_TRUE;
287     } else {
288         if (verbose) {
289             printf( "env: PR_GetEnv() after RAW un-set found: %s\n", value );
290         }
291     }
292 
293     /* ---------------------------------------------------------------------- */
294     /* set it again ... */
295     envBuf = NewBuffer( ENVBUFSIZE );
296     sprintf( envBuf, ENVNAME "=" ENVVALUE );
297     rc = PR_SetEnv( envBuf );
298     if ( PR_FAILURE == rc )  {
299         if (debug) {
300             printf( "env: PR_SetEnv() failed setting the second time.\n");
301         }
302         failedAlready = PR_TRUE;
303     } else {
304         if (verbose) {
305             printf("env: PR_SetEnv() worked.\n");
306         }
307     }
308 
309     /* un-set the variable using the form name= */
310     envBuf = NewBuffer( ENVBUFSIZE );
311     sprintf( envBuf, ENVNAME "=" );
312     rc = PR_SetEnv( envBuf );
313     if ( PR_FAILURE == rc )  {
314         if (debug) {
315             printf( "env: PR_SetEnv() failed un-setting using name=\n");
316         }
317         failedAlready = PR_TRUE;
318     } else {
319         if (verbose) {
320             printf("env: PR_SetEnv() un-set using name= worked\n" );
321         }
322     }
323 
324     value = PR_GetEnv( ENVNAME );
325     if (( NULL == value ) || ( 0x00 == *value )) {
326         if (verbose) {
327             printf("env: PR_GetEnv() after un-set using name= worked\n" );
328         }
329     } else {
330         if (debug) {
331             printf( "env: PR_GetEnv() after un-set using name=. Found: %s\n", value );
332         }
333         failedAlready = PR_TRUE;
334     }
335     /* ---------------------------------------------------------------------- */
336     /* un-set the variable using the form name= */
337     envBuf = NewBuffer( ENVBUFSIZE );
338     sprintf( envBuf, ENVNAME "999=" );
339     rc = PR_SetEnv( envBuf );
340     if ( PR_FAILURE == rc )  {
341         if (debug) {
342             printf( "env: PR_SetEnv() failed un-setting using name=\n");
343         }
344         failedAlready = PR_TRUE;
345     } else {
346         if (verbose) {
347             printf("env: PR_SetEnv() un-set using name= worked\n" );
348         }
349     }
350 
351     value = PR_GetEnv( ENVNAME "999" );
352     if (( NULL == value ) || ( 0x00 == *value )) {
353         if (verbose) {
354             printf("env: PR_GetEnv() after un-set using name= worked\n" );
355         }
356     } else {
357         if (debug) {
358             printf( "env: PR_GetEnv() after un-set using name=. Found: %s\n", value );
359         }
360         failedAlready = PR_TRUE;
361     }
362 
363     /* ---------------------------------------------------------------------- */
364     if (debug || verbose) {
365         printf("\n%s\n", (failedAlready)? "FAILED" : "PASSED" );
366     }
367     return( (failedAlready)? 1 : 0 );
368 }  /* main() */
369 
370 /* env.c */
371