gsasl  1.10.0
About: GNU SASL is an implementation of the Simple Authentication and Security Layer (SASL). Development version.
  Fossies Dox: gsasl-1.10.0.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

setenv.c
Go to the documentation of this file.
1 /* Copyright (C) 1992, 1995-2003, 2005-2021 Free Software Foundation, Inc.
2  This file is part of the GNU C Library.
3 
4  This program is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 3 of the License, or
7  (at your option) any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program. If not, see <https://www.gnu.org/licenses/>. */
16 
17 #if !_LIBC
18 /* Don't use __attribute__ __nonnull__ in this compilation unit. Otherwise gcc
19  optimizes away the name == NULL test below. */
20 # define _GL_ARG_NONNULL(params)
21 
22 # define _GL_USE_STDLIB_ALLOC 1
23 # include <config.h>
24 #endif
25 
26 #include <alloca.h>
27 
28 /* Specification. */
29 #include <stdlib.h>
30 
31 #include <errno.h>
32 #ifndef __set_errno
33 # define __set_errno(ev) ((errno) = (ev))
34 #endif
35 
36 #include <string.h>
37 #if _LIBC || HAVE_UNISTD_H
38 # include <unistd.h>
39 #endif
40 
41 #if !_LIBC
42 # include "malloca.h"
43 #endif
44 
45 #if _LIBC || !HAVE_SETENV
46 
47 #if !_LIBC
48 # define __environ environ
49 #endif
50 
51 #if _LIBC
52 /* This lock protects against simultaneous modifications of 'environ'. */
53 # include <bits/libc-lock.h>
54 __libc_lock_define_initialized (static, envlock)
55 # define LOCK __libc_lock_lock (envlock)
56 # define UNLOCK __libc_lock_unlock (envlock)
57 #else
58 # define LOCK
59 # define UNLOCK
60 #endif
61 
62 /* In the GNU C library we must keep the namespace clean. */
63 #ifdef _LIBC
64 # define setenv __setenv
65 # define clearenv __clearenv
66 # define tfind __tfind
67 # define tsearch __tsearch
68 #endif
69 
70 /* In the GNU C library implementation we try to be more clever and
71  allow arbitrarily many changes of the environment given that the used
72  values are from a small set. Outside glibc this will eat up all
73  memory after a while. */
74 #if defined _LIBC || (defined HAVE_SEARCH_H && defined HAVE_TSEARCH \
75  && (defined __GNUC__ || defined __clang__))
76 # define USE_TSEARCH 1
77 # include <search.h>
78 typedef int (*compar_fn_t) (const void *, const void *);
79 
80 /* This is a pointer to the root of the search tree with the known
81  values. */
82 static void *known_values;
83 
84 # define KNOWN_VALUE(Str) \
85  ({ \
86  void *value = tfind (Str, &known_values, (compar_fn_t) strcmp); \
87  value != NULL ? *(char **) value : NULL; \
88  })
89 # define STORE_VALUE(Str) \
90  tsearch (Str, &known_values, (compar_fn_t) strcmp)
91 
92 #else
93 # undef USE_TSEARCH
94 
95 # define KNOWN_VALUE(Str) NULL
96 # define STORE_VALUE(Str) do { } while (0)
97 
98 #endif
99 
100 
101 /* If this variable is not a null pointer we allocated the current
102  environment. */
103 static char **last_environ;
104 
105 
106 /* This function is used by 'setenv' and 'putenv'. The difference between
107  the two functions is that for the former must create a new string which
108  is then placed in the environment, while the argument of 'putenv'
109  must be used directly. This is all complicated by the fact that we try
110  to reuse values once generated for a 'setenv' call since we can never
111  free the strings. */
112 int
113 __add_to_environ (const char *name, const char *value, const char *combined,
114  int replace)
115 {
116  char **ep;
117  size_t size;
118  const size_t namelen = strlen (name);
119  const size_t vallen = value != NULL ? strlen (value) + 1 : 0;
120 
121  LOCK;
122 
123  /* We have to get the pointer now that we have the lock and not earlier
124  since another thread might have created a new environment. */
125  ep = __environ;
126 
127  size = 0;
128  if (ep != NULL)
129  {
130  for (; *ep != NULL; ++ep)
131  if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=')
132  break;
133  else
134  ++size;
135  }
136 
137  if (ep == NULL || *ep == NULL)
138  {
139  char **new_environ;
140 #ifdef USE_TSEARCH
141  char *new_value;
142 #endif
143 
144  /* We allocated this space; we can extend it. */
145  new_environ =
146  (char **) (last_environ == NULL
147  ? malloc ((size + 2) * sizeof (char *))
148  : realloc (last_environ, (size + 2) * sizeof (char *)));
149  if (new_environ == NULL)
150  {
151  /* It's easier to set errno to ENOMEM than to rely on the
152  'malloc-posix' and 'realloc-posix' gnulib modules. */
153  __set_errno (ENOMEM);
154  UNLOCK;
155  return -1;
156  }
157 
158  /* If the whole entry is given add it. */
159  if (combined != NULL)
160  /* We must not add the string to the search tree since it belongs
161  to the user. */
162  new_environ[size] = (char *) combined;
163  else
164  {
165  /* See whether the value is already known. */
166 #ifdef USE_TSEARCH
167 # ifdef _LIBC
168  new_value = (char *) alloca (namelen + 1 + vallen);
169  __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
170  value, vallen);
171 # else
172  new_value = (char *) malloca (namelen + 1 + vallen);
173  if (new_value == NULL)
174  {
175  __set_errno (ENOMEM);
176  UNLOCK;
177  return -1;
178  }
179  memcpy (new_value, name, namelen);
180  new_value[namelen] = '=';
181  memcpy (&new_value[namelen + 1], value, vallen);
182 # endif
183 
184  new_environ[size] = KNOWN_VALUE (new_value);
185  if (new_environ[size] == NULL)
186 #endif
187  {
188  new_environ[size] = (char *) malloc (namelen + 1 + vallen);
189  if (new_environ[size] == NULL)
190  {
191 #if defined USE_TSEARCH && !defined _LIBC
192  freea (new_value);
193 #endif
194  __set_errno (ENOMEM);
195  UNLOCK;
196  return -1;
197  }
198 
199 #ifdef USE_TSEARCH
200  memcpy (new_environ[size], new_value, namelen + 1 + vallen);
201 #else
202  memcpy (new_environ[size], name, namelen);
203  new_environ[size][namelen] = '=';
204  memcpy (&new_environ[size][namelen + 1], value, vallen);
205 #endif
206  /* And save the value now. We cannot do this when we remove
207  the string since then we cannot decide whether it is a
208  user string or not. */
209  STORE_VALUE (new_environ[size]);
210  }
211 #if defined USE_TSEARCH && !defined _LIBC
212  freea (new_value);
213 #endif
214  }
215 
216  if (__environ != last_environ)
217  memcpy ((char *) new_environ, (char *) __environ,
218  size * sizeof (char *));
219 
220  new_environ[size + 1] = NULL;
221 
222  last_environ = __environ = new_environ;
223  }
224  else if (replace)
225  {
226  char *np;
227 
228  /* Use the user string if given. */
229  if (combined != NULL)
230  np = (char *) combined;
231  else
232  {
233 #ifdef USE_TSEARCH
234  char *new_value;
235 # ifdef _LIBC
236  new_value = alloca (namelen + 1 + vallen);
237  __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
238  value, vallen);
239 # else
240  new_value = malloca (namelen + 1 + vallen);
241  if (new_value == NULL)
242  {
243  __set_errno (ENOMEM);
244  UNLOCK;
245  return -1;
246  }
247  memcpy (new_value, name, namelen);
248  new_value[namelen] = '=';
249  memcpy (&new_value[namelen + 1], value, vallen);
250 # endif
251 
252  np = KNOWN_VALUE (new_value);
253  if (np == NULL)
254 #endif
255  {
256  np = (char *) malloc (namelen + 1 + vallen);
257  if (np == NULL)
258  {
259 #if defined USE_TSEARCH && !defined _LIBC
260  freea (new_value);
261 #endif
262  __set_errno (ENOMEM);
263  UNLOCK;
264  return -1;
265  }
266 
267 #ifdef USE_TSEARCH
268  memcpy (np, new_value, namelen + 1 + vallen);
269 #else
270  memcpy (np, name, namelen);
271  np[namelen] = '=';
272  memcpy (&np[namelen + 1], value, vallen);
273 #endif
274  /* And remember the value. */
275  STORE_VALUE (np);
276  }
277 #if defined USE_TSEARCH && !defined _LIBC
278  freea (new_value);
279 #endif
280  }
281 
282  *ep = np;
283  }
284 
285  UNLOCK;
286 
287  return 0;
288 }
289 
290 int
291 setenv (const char *name, const char *value, int replace)
292 {
293  if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
294  {
295  __set_errno (EINVAL);
296  return -1;
297  }
298 
299  return __add_to_environ (name, value, NULL, replace);
300 }
301 
302 /* The 'clearenv' was planned to be added to POSIX.1 but probably
303  never made it. Nevertheless the POSIX.9 standard (POSIX bindings
304  for Fortran 77) requires this function. */
305 int
306 clearenv (void)
307 {
308  LOCK;
309 
310  if (__environ == last_environ && __environ != NULL)
311  {
312  /* We allocated this environment so we can free it. */
313  free (__environ);
314  last_environ = NULL;
315  }
316 
317  /* Clear the environment pointer removes the whole environment. */
318  __environ = NULL;
319 
320  UNLOCK;
321 
322  return 0;
323 }
324 
325 #ifdef _LIBC
326 static void
327 free_mem (void)
328 {
329  /* Remove all traces. */
330  clearenv ();
331 
332  /* Now remove the search tree. */
333  __tdestroy (known_values, free);
334  known_values = NULL;
335 }
336 text_set_element (__libc_subfreeres, free_mem);
337 
338 
339 # undef setenv
340 # undef clearenv
341 weak_alias (__setenv, setenv)
342 weak_alias (__clearenv, clearenv)
343 #endif
344 
345 #endif /* _LIBC || !HAVE_SETENV */
346 
347 /* The rest of this file is called into use when replacing an existing
348  but buggy setenv. Known bugs include failure to diagnose invalid
349  name, and consuming a leading '=' from value. */
350 #if HAVE_SETENV
351 
352 # undef setenv
353 # if !HAVE_DECL_SETENV
354 extern int setenv (const char *, const char *, int);
355 # endif
356 # define STREQ(a, b) (strcmp (a, b) == 0)
357 
358 int
359 rpl_setenv (const char *name, const char *value, int replace)
360 {
361  int result;
362  if (!name || !*name || strchr (name, '='))
363  {
364  errno = EINVAL;
365  return -1;
366  }
367  /* Call the real setenv even if replace is 0, in case implementation
368  has underlying data to update, such as when environ changes. */
369  result = setenv (name, value, replace);
370  if (result == 0 && replace && *value == '=')
371  {
372  char *tmp = getenv (name);
373  if (!STREQ (tmp, value))
374  {
375  int saved_errno;
376  size_t len = strlen (value);
377  tmp = malloca (len + 2);
378  /* Since leading '=' is eaten, double it up. */
379  *tmp = '=';
380  memcpy (tmp + 1, value, len + 1);
381  result = setenv (name, tmp, replace);
382  saved_errno = errno;
383  freea (tmp);
384  errno = saved_errno;
385  }
386  }
387  return result;
388 }
389 
390 #endif /* HAVE_SETENV */
#define alloca(size)
Definition: getopt.c:56
void freea(void *p)
Definition: malloca.c:83
#define malloca(N)
Definition: malloca.h:58
#define NULL
Definition: stddef.in.h:72
#define STREQ(a, b)
Definition: macros.h:104
static gss_OID_desc tmp
Definition: gss-extra.c:38
const char * name
Definition: error.c:43
#define weak_alias(name, aliasname)
Definition: libc-config.h:179
#define LOCK
Definition: setenv.c:58
static char ** last_environ
Definition: setenv.c:103
int setenv(const char *name, const char *value, int replace)
Definition: setenv.c:291
#define STORE_VALUE(Str)
Definition: setenv.c:96
int __add_to_environ(const char *name, const char *value, const char *combined, int replace)
Definition: setenv.c:113
#define KNOWN_VALUE(Str)
Definition: setenv.c:95
#define __environ
Definition: setenv.c:48
#define UNLOCK
Definition: setenv.c:59
int clearenv(void)
Definition: setenv.c:306
#define __set_errno(ev)
Definition: setenv.c:33