/[pdpsoft]/trunk/grid-mw-security/cgul/environ/environ.c
ViewVC logotype

Contents of /trunk/grid-mw-security/cgul/environ/environ.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2087 - (show annotations) (download) (as text)
Thu Nov 11 15:33:33 2010 UTC (11 years, 8 months ago) by msalle
File MIME type: text/x-chdr
File size: 19011 byte(s)
Bringing environ back in sync with glexec: 
- new function int cgul_unsetenv_dst() needed to remove an entry from an 'saved'
  environment.

1 /**
2 * Copyright (c) Members of the EGEE Collaboration. 2010.
3 * See http://www.eu-egee.org/partners/ for details on the copyright
4 * holders.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * Authors: Oscar Koeroo, Mischa Sall\'e, Aram Verstegen
19 * NIKHEF Amsterdam, the Netherlands
20 * <grid-mw-security@nikhef.nl>
21 */
22
23 #include <unistd.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdio.h>
27
28 #include "environ.h"
29
30 /**
31 * returns number of entries in NULL terminated string array, such as argv and
32 * environ(7). In case list is NULL it also returns 0.
33 */
34 size_t cgul_strarrlen(const char **list) {
35 int entries;
36 /* Check if list exists: prevents common segfault situation */
37 if (!list) return 0;
38 /* Now loop over its entries */
39 for(entries=0; list[entries]; entries++);
40 return (size_t)entries;
41 }
42
43 /**
44 * returns the number of entries in list which start with pattern. If pattern of
45 * list is NULL it also returns 0.
46 */
47 size_t cgul_patternentries(env_t list, const char *pattern) {
48 int i,match=0;
49 size_t patlen;
50 /* Check if list exists: prevents common segfault situation */
51 if (!list || !pattern)
52 return 0;
53 patlen=strlen(pattern);
54 /* Now loop over its entries */
55 for(i=0; list[i]; i++) {
56 if (strncmp(list[i],pattern,patlen)==0)
57 match++;
58 }
59 return (size_t)match;
60 }
61
62 /**
63 * Returns the length of the name part of the var=value pair or -1 when there is
64 * no '=' sign.
65 */
66 int cgul_getvarnamelen(const char *varname) {
67 char *pos;
68 /* find first '=' */
69 if (!varname)
70 return -1;
71 pos=strchr(varname,'=');
72 if (pos==NULL) /* not var=value */
73 return -1;
74 return (int)strlen(varname)-(int)strlen(pos); /* no pointer arithmetics */
75 }
76
77
78 /**
79 * Finds name for given var=value pair in namevalue. varname is a buffer
80 * which will contain the result and has space for maxvarnamelen chars.
81 * Returns integer, negative on error, -1 on no '=' sign, -2 name too long;
82 * 0 success
83 */
84 int cgul_getvarname(char *varname,const int maxvarnamelen,
85 const char *namevalue) {
86 int varnamelen;
87
88 if ((varnamelen=cgul_getvarnamelen(namevalue))==-1)
89 return -1;
90 if (varnamelen>maxvarnamelen)
91 return -2;
92 strncpy(varname,namevalue,(size_t)varnamelen);
93 varname[varnamelen]='\0';
94
95 return 0;
96 }
97
98 /**
99 * Finds index in **src matching variable name, in case of no match (including
100 * env==NULL) returns -1
101 */
102 int cgul_getvarindex(const env_t src, const char *varname) {
103 int i;
104 size_t len;
105
106 if (src==NULL || varname==NULL)
107 return -1;
108
109 len=strlen(varname);
110 /* Loop over env */
111 for (i=0; src[i]; i++) {
112 if (strncmp(src[i],varname,len)==0 && src[i][len]=='=')
113 /* Found match */
114 return i;
115 }
116 /* NO match found */
117 return -1;
118 }
119
120 /**
121 * Finds the value of varname in src list. Returns NULL when no match, incl.
122 * NULL valued src or varname.
123 */
124 char *cgul_getenv_src(const env_t src, char *varname) {
125 int i;
126 size_t len;
127 char *match;
128
129 /* Don't use getvarindex, since this saves us one strlen (-: */
130 if (src==NULL || varname==NULL)
131 return NULL;
132
133 len=strlen(varname);
134 /* Loop over env */
135 for (i=0; src[i]; i++) {
136 if (strncmp(src[i],varname,len)==0 && src[i][len]=='=') {
137 /* Found match */
138 match=&(src[i][len+1]);
139 return match;
140 }
141 }
142 /* NO match found */
143 return NULL;
144 }
145
146 /**
147 * As unsetenv(3) but using var=value pair, specified in namevalue. The maximum
148 * var length is MAXVARNAMELEN. See also putenv(3).
149 * Returns integer, 0 on success, negative on error.
150 */
151 int cgul_unsetenvpair(const char *namevalue) {
152 char varname[MAXENVVARNAMELEN];
153 int rc;
154
155 /* Get variable name for var=value pair */
156 if ((rc=cgul_getvarname(varname,MAXENVVARNAMELEN,namevalue))!=0)
157 return rc;
158 /* Unset variable */
159 if (unsetenv(varname))
160 return -1;
161
162 return 0;
163 }
164
165 /**
166 * Clears the entire environment
167 * Returns integer, -1 on error, 0 on success
168 */
169 int cgul_clear_env(void) {
170 while(environ[0]) {
171 if (cgul_unsetenvpair(environ[0]))
172 return -1;
173 }
174 return 0;
175 }
176
177 /*
178 * Clears the environment of all variables starting with pattern, case
179 * INsensitive.
180 * Returns number of cleaned entries, -1 on error.
181 */
182 int cgul_clear_env_pattern(const char *pattern) {
183 int i=0,match=0,rc;
184 size_t patlen;
185
186 if (!pattern)
187 return -1;
188 patlen=strlen(pattern);
189 while(environ[i]) {
190 if (strncasecmp(pattern,environ[i],patlen)==0) {
191 if ((rc=cgul_unsetenvpair(environ[i])))
192 return rc;
193 match++;
194 } else
195 i++; /* only increase when we haven't just removed an entry... */
196 }
197 return match;
198 }
199
200
201 /**
202 * Creates a duplicate of src. In case *dst!=NULL it will be used and should be
203 * big enough. Otherwise space is malloc-ed. dst is only updated upon success.
204 * Returns -1 upon error, 0 on success.
205 */
206 int cgul_copy_env(env_t *dst,const env_t src) {
207 int i,j;
208 size_t envlen;
209 env_t newenv=*dst;
210
211 /* If no dst exists, malloc it. */
212 if (newenv==NULL) {
213 envlen=cgul_strarrlen((const char**)src);
214 newenv=(env_t)malloc((envlen+1)*sizeof(char*));
215 if (newenv==NULL)
216 return -1;
217 }
218
219 /* Copy src to newenv */
220 for (i=0; src[i]; i++) {
221 if ( (newenv[i]=strdup(src[i]))==NULL ) {
222 /* Error: cleanup memory and reset */
223 for (j=0; j<i; j++)
224 free(newenv[j]);
225 if (*dst==NULL)
226 free(newenv);
227 return -1;
228 }
229 }
230 /* Finalize the new environ */
231 newenv[i]=NULL;
232 if (*dst==NULL)
233 *dst=newenv;
234
235 return 0;
236 }
237
238 /**
239 * Same as copy_env() but first unsets all environment variables starting with
240 * MALLOC, case INsensitive. dst is again only updated upon success.
241 * Returns -1 upon error, 0 on success.
242 */
243 int cgul_safe_copy_env(env_t *dst,const env_t src) {
244 /* Clean all MALLOC* variables */
245 if (cgul_clear_env_pattern("MALLOC"))
246 return -1;
247
248 return cgul_copy_env(dst,src);
249 }
250
251 /**
252 * Creates a list of the var=value pairs from src which have varname in list.
253 * If it fails NULL is returned. This can also be done using add_src_list()
254 * using dst==NULL, but this is more efficiently coded. All new entries are
255 * strdup-ed from those in src.
256 */
257 env_t cgul_copy_src_list(const env_t src,const char *list[]) {
258 int i,j,src_idx,match=0;
259 size_t listlen=cgul_strarrlen(list);
260 env_t newenv;
261
262 /* Malloc space */
263 newenv=(env_t)malloc((listlen+1)*sizeof(char*));
264 if (newenv==NULL)
265 return NULL;
266
267 /* IMPORTANT: list must be NULL terminated! */
268 newenv[0]=NULL;
269
270 /* Only do when list exists, otherwise return empty list, but not NO list!
271 * Note it's not an error, just an empty list. */
272 if (src==NULL || list==NULL)
273 return newenv;
274
275 /* loop over list: Note we can have unmatched entries: match counts */
276 for (i=0; list[i]; i++) {
277 /* Look if list[i] is in src */
278 if ( (src_idx=cgul_getvarindex(src,list[i])) >= 0) {
279 /* Don't! check for duplicates... */
280 /* substitute existing: first try strdup */
281 if ((newenv[match]=strdup(src[src_idx]))==NULL) {
282 /* error: cleanup */
283 for (j=0; j<match; j++) {
284 free(newenv[j]); newenv[j]=NULL;
285 }
286 free(newenv);
287 return NULL;
288 }
289 match++;
290 /* Don't forget the final NULL pointer! */
291 newenv[match]=NULL;
292 }
293 }
294 return newenv;
295 }
296
297 /**
298 * Adds to dst the var=value pairs from src which have varname in list.
299 * All entries will be strdup-ed from those in src.
300 * If *dst is NULL, it will be malloc-ed, otherwise it will be realloc-ed.
301 * Upon success returns 0. On error -1 is returned. If part of the environment
302 * has been successfully copied, they will stay part of the environment.
303 * See also copy_src_list() which is more efficient when dst is NULL !
304 */
305 int cgul_add_src_list(env_t *dst,const env_t src,const char **list) {
306 int i,src_idx,dst_idx,match;
307 env_t newenv=*dst;
308 size_t dstlen,listlen;
309 char *dummy;
310
311 listlen=cgul_strarrlen(list);
312 /* Create space for combined array, might be too much if list is not fully
313 * used or partially replaces old entries, but more efficient (single
314 * realloc() call).
315 * Note that we check for empty list AFTER the malloc, and BEFORE the
316 * realloc */
317 if (newenv==NULL) {
318 dstlen=0;
319 newenv=(env_t)malloc((listlen+1)*sizeof(char*));
320 if (newenv==NULL)
321 return -1;
322 *dst=newenv; /* update *dst after malloc */
323 /* IMPORTANT: list must be NULL terminated! */
324 newenv[0]=NULL;
325 /* Only continue when list and src exist, do alloc in this case, since
326 * dst shouldn't return empty. Not an error. */
327 if (list==NULL || src==NULL)
328 return 0;
329 } else {
330 /* Only do when list and src exist, no need to realloc, not an error. */
331 if (list==NULL || src==NULL)
332 return 0;
333 /* Count length of existing list */
334 dstlen=cgul_strarrlen((const char **)*dst);
335 newenv=(env_t)realloc(newenv,(dstlen+listlen+1)*sizeof(char*));
336 if (newenv==NULL)
337 return -1;
338 *dst=newenv; /* update *dst after realloc */
339 }
340
341 match=0;
342 /* loop over list: Note we can have unmatched entries: match counts */
343 for (i=0; list[i]; i++) {
344 /* Look if list[i] is in src */
345 if ( (src_idx=cgul_getvarindex(src,list[i])) >= 0) {
346 /* Make already a copy, we need it in any case */
347 if ( (dummy=strdup(src[src_idx])) == NULL)
348 /* Out of mem: cannot cleanup anymore, might have
349 * substituted entries */
350 return -1;
351 /* Look for list[i] in newenv: we might have it already. Note
352 * that this is not checked when using copy_src_list() */
353 if ( (dst_idx=cgul_getvarindex((const env_t)newenv,list[i])) >= 0) {
354 /* REPLACE: substitute existing: first try strdup */
355 /* Now substitute: free old entry in newenv and link to new
356 * entry */
357 free(newenv[dst_idx]);
358 newenv[dst_idx]=dummy;
359 } else {
360 /* ADD: create new one */
361 newenv[dstlen+match++]=dummy; /* created new entry: update match */
362 newenv[dstlen+match]=NULL; /* keep env NULL terminated */
363 }
364 }
365 }
366 return 0;
367 }
368
369 /**
370 * Adds to dst the var=value pairs from src which start with pattern.
371 * All entries will be strdup-ed from those in src.
372 * If *dst is NULL, it will be malloc-ed, otherwise it will be realloc-ed.
373 * Upon success returns the number of matches. On error -1 is returned, if part
374 * of the environment has been successfully copied, they will stay part of the
375 * environment.
376 * An empty pattern (either "" or NULL) or src is NOT considered error.
377 * See also cgul_add_src_list()
378 */
379 int cgul_add_src_pattern(env_t *dst,const env_t src,const char *pattern) {
380 int numpat,i,j,not_matched,match=0;
381 env_t newenv=*dst;
382 size_t dstlen,patlen,namelen;
383 char *namevaluecopy;
384
385 numpat=cgul_patternentries(src,pattern);
386 /* Create space for combined array, might be too much if list is not fully
387 * used or partially replaces old entries, but more efficient (single
388 * realloc() call).
389 * Note that we check for empty list AFTER the malloc, and BEFORE the
390 * realloc */
391 if (newenv==NULL) {
392 dstlen=0;
393 newenv=(env_t)malloc((numpat+1)*sizeof(char*));
394 if (newenv==NULL)
395 return -1;
396 *dst=newenv; /* update *dst after malloc */
397 /* IMPORTANT: list must be NULL terminated! */
398 newenv[0]=NULL;
399 /* Only continue when list and src exist, do alloc in this case, since
400 * dst shouldn't return empty. Not an error. */
401 if (pattern==NULL || src==NULL)
402 return 0;
403 } else {
404 /* Only do when list and src exist, no need to realloc, not an error. */
405 if (pattern==NULL || src==NULL)
406 return 0;
407 /* Count length of existing list */
408 dstlen=cgul_strarrlen((const char **)*dst);
409 newenv=(env_t)realloc(newenv,(dstlen+numpat+1)*sizeof(char*));
410 if (newenv==NULL)
411 return -1;
412 *dst=newenv; /* update *dst after realloc */
413 }
414 /* Make sure all unset entries are NULL */
415 for (i=dstlen+1; i<dstlen+numpat+1; i++) newenv[i]=NULL;
416
417 patlen=strlen(pattern);
418 /* loop over src */
419 for (i=0; src[i]; i++) {
420 /* Look if src[i] matches pattern */
421 if (strncmp(src[i],pattern,patlen)==0) {
422 /* Look for length of name part (negative = means no name) */
423 if ( (namelen=cgul_getvarnamelen(src[i])) < 0)
424 break;
425 /* Make already a copy, we need it in any case */
426 if ( (namevaluecopy=strdup(src[i])) == NULL)
427 /* Out of mem: cannot cleanup anymore, might have substituted
428 * entries */
429 return -1;
430 /* look for possibly existing entry */
431 not_matched=1;
432 for (j=0; not_matched && newenv[j]; j++) {
433 if (strncmp(newenv[j],namevaluecopy,namelen)==0 &&
434 newenv[j][namelen]=='=') {
435 /* REPLACE: substitute existing */
436 free(newenv[j]); /* free old */
437 newenv[j]=namevaluecopy; /* set new */
438 not_matched=0; /* found match -> done */
439 }
440 }
441 if (not_matched) {
442 /* ADD: no old match */
443 newenv[dstlen+match++]=namevaluecopy; /* created new entry:
444 update match */
445 newenv[dstlen+match]=NULL; /* keep env NULL terminated */
446 }
447 }
448 }
449 return match;
450 }
451
452 /**
453 * adds var=value pair to dst. If the variable already exists, it's entry is
454 * replaced. Otherwise *dst is realloc-ed and a new entry is added, the
455 * resulting array is returned.
456 * Upon success returns 0. In case of error -1 is returned and dst remains
457 * unchanged. namevalue is strdup-ed into dst and hence can be freed by the
458 * caller (unlike putenv(3p) )
459 */
460 int cgul_add_namevalue(env_t *dst,const char *namevalue) {
461 int i,namelen;
462 size_t dstlen;
463 char *namevaluecopy;
464 env_t newenv=*dst;
465
466 /* Look for length of name part (no = means no name) */
467 if ( (namelen=cgul_getvarnamelen(namevalue)) < 0)
468 return -1;
469 /* Make already a copy, we need it in any case, unless realloc fails */
470 if ( (namevaluecopy=strdup(namevalue)) == NULL)
471 return -1;
472 /* look for existing entry */
473 for (i=0; newenv[i]; i++) {
474 if (strncmp(namevalue,newenv[i],namelen)==0 && newenv[i][namelen]=='=')
475 {
476 free(newenv[i]);
477 newenv[i]=namevaluecopy;
478 return 0;
479 }
480 }
481 /* No old match, make a new entry, add two, because strarrlen doesn't count
482 * the NULL string at the end. First create new entry, since that's easier
483 * to undo. */
484 dstlen=cgul_strarrlen((const char**)newenv);
485 newenv=(env_t)realloc(newenv,(dstlen+2)*sizeof(char*));
486 if (newenv==NULL) {
487 free(namevaluecopy);
488 return -1;
489 }
490 *dst=newenv; /* update *dst after (re/m)alloc */
491 newenv[dstlen]=namevaluecopy;
492 newenv[dstlen+1]=NULL;
493
494 return 0;
495 }
496
497 /**
498 * adds name=value pair to dst, as in setenv() with a 'external environment' .
499 * If the variable already exists, it's entry is replaced. Otherwise *dst is
500 * realloc-ed and a new entry is added.
501 * Upon success returns 0. In case of error -1 is returned and dst remains
502 * unchanged. name and value can be freed by the caller (unlike putenv(3p) )
503 */
504 int cgul_setenv_dst(env_t *dst,const char *name, const char *value) {
505 int i,dstlen;
506 size_t namelen,valuelen,totallen;
507 char *namevalue;
508 const char *realvalue;
509 env_t newenv=*dst;
510
511 /* Check arguments */
512 if (name==NULL)
513 return -1;
514 if (value==NULL) {
515 realvalue="";
516 valuelen=0;
517 } else {
518 realvalue=value;
519 valuelen=strlen(realvalue);
520 }
521 namelen=strlen(name);
522 /* Add two: '=' and '\0' */
523 totallen=namelen+valuelen+2*sizeof(char);
524 if ((namevalue=(char*)malloc(totallen))==NULL)
525 return -1;
526 sprintf(namevalue,"%s=%s",name,realvalue);
527
528 /* look for existing entry */
529 for (i=0; newenv[i]; i++) {
530 if (strncmp(name,newenv[i],namelen)==0 && newenv[i][namelen]=='=') {
531 free(newenv[i]);
532 newenv[i]=namevalue;
533 return 0;
534 }
535 }
536 /* No old match, make a new entry, add two, because strarrlen doesn't count
537 * the NULL string at the end. */
538 dstlen=cgul_strarrlen((const char **)newenv);
539 newenv=(env_t)realloc(newenv,(dstlen+2)*sizeof(char*));
540 if (newenv==NULL) {
541 free(namevalue);
542 return -1;
543 }
544 *dst=newenv; /* update *dst after (re/m)alloc */
545 newenv[dstlen]=namevalue;
546 newenv[dstlen+1]=NULL;
547
548 return 0;
549 }
550
551 /**
552 * Removes a variable from dst as in unsetenv() with a 'external environment'.
553 */
554 int cgul_unsetenv_dst(env_t *dst,const char *name) {
555 int namelen,i;
556 env_t newenv=*dst;
557 int entry=-1;
558
559 /* Check arguments */
560 if (name==NULL)
561 return -1;
562 namelen=strlen(name);
563
564 /* look for existing entry */
565 for (i=0; newenv[i]; i++) {
566 if (strncmp(name,newenv[i],namelen)==0 && newenv[i][namelen]=='=') {
567 entry=i;
568 break;
569 }
570 }
571 /* no match */
572 if (entry<0) return 0;
573
574 /* Remainder of list... */
575 for (; newenv[i]; i++);
576
577 /* Now clean entry if it's there and swap with the last in the list */
578 free(newenv[entry]);
579
580 /* If there were more than one elements, move the last to the removed one */
581 if (i>0) {
582 newenv[entry]=newenv[i-1]; /* last element */
583 newenv[i-1]=NULL;
584 } else
585 newenv[entry]=NULL;
586 return 0;
587 }
588
589 /**
590 * Adds to the current environment the var=value pairs from src which have
591 * varname in list. Returns number of entries added or -1 on error.
592 * NOTE: we do a strdup before the actual putenv, so even though putenv doesn't
593 * reserve new memory, we stil can free src !
594 */
595 int cgul_putenv_src_list(env_t src,const char **list) {
596 int i,src_idx,match=0;
597 char *dummy;
598
599 /* Only do when list exists...*/
600 if (!list)
601 return 0;
602
603 /* loop over list */
604 for (i=0; list[i]; i++) {
605 if ((src_idx=cgul_getvarindex((const env_t)src,list[i]))>=0) {
606 /* Found match */
607 /* Make copy, so that src eventually can be freed! */
608 if ( (dummy=strdup(src[src_idx]))==NULL )
609 return -1;
610 /* Now do the putenv */
611 if (putenv(dummy))
612 return -1;
613 match++;
614 }
615 }
616 return match;
617 }
618
619 /**
620 * Adds to the current environment the var=value pairs from src which start with
621 * pattern. Returns number of entries added or -1 on error.
622 * NOTE: we do a strdup before the actual putenv, so even though putenv doesn't
623 * reserve new memory, we stil can free src !
624 */
625 int cgul_putenv_src_pattern(env_t src,const char *pattern) {
626 int i,match=0;
627 size_t len;
628 char *dummy;
629
630 if (!pattern)
631 return -1;
632 len=strlen(pattern);
633 /* loop over src environ */
634 for (i=0; src[i]; i++) {
635 if (strncmp(src[i],pattern,len)==0) {
636 /* Found match */
637 /* Make copy, so that src eventually can be freed! */
638 if ( (dummy=strdup(src[i]))==NULL )
639 return -1;
640 /* Now do the putenv */
641 if (putenv(dummy))
642 return -1;
643 match++;
644 }
645 }
646 return match;
647 }
648

grid.support@nikhef.nl
ViewVC Help
Powered by ViewVC 1.1.28