]> granicus.if.org Git - shadow/blob - libmisc/env.c
da03ac4e2cce8daabfdab682572b3969c10c3e81
[shadow] / libmisc / env.c
1 /*
2  * Copyright (c) 1989 - 1992, Julianne Frances Haugh
3  * Copyright (c) 1996 - 1999, Marek Michałkiewicz
4  * Copyright (c) 2003 - 2005, Tomasz Kłoczko
5  * Copyright (c) 2008       , Nicolas François
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the copyright holders or contributors may not be used to
17  *    endorse or promote products derived from this software without
18  *    specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
24  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include <config.h>
34
35 #ident "$Id$"
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include "prototypes.h"
41 #include "defines.h"
42 /*
43  * NEWENVP_STEP must be a power of two.  This is the number
44  * of (char *) pointers to allocate at a time, to avoid using
45  * realloc() too often.
46  */
47 #define NEWENVP_STEP 16
48 size_t newenvc = 0;
49 char **newenvp = NULL;
50 extern char **environ;
51
52 static const char *forbid[] = {
53         "_RLD_=",
54         "BASH_ENV=",            /* GNU creeping featurism strikes again... */
55         "ENV=",
56         "HOME=",
57         "IFS=",
58         "KRB_CONF=",
59         "LD_",                  /* anything with the LD_ prefix */
60         "LIBPATH=",
61         "MAIL=",
62         "NLSPATH=",
63         "PATH=",
64         "SHELL=",
65         "SHLIB_PATH=",
66         (char *) 0
67 };
68
69 /* these are allowed, but with no slashes inside
70    (to work around security problems in GNU gettext) */
71 static const char *noslash[] = {
72         "LANG=",
73         "LANGUAGE=",
74         "LC_",                  /* anything with the LC_ prefix */
75         (char *) 0
76 };
77
78 /*
79  * initenv() must be called once before using addenv().
80  */
81 void initenv (void)
82 {
83         newenvp = (char **) xmalloc (NEWENVP_STEP * sizeof (char *));
84         *newenvp = NULL;
85 }
86
87
88 void addenv (const char *string, const char *value)
89 {
90         char *cp, *newstring;
91         size_t i;
92         size_t n;
93
94         if (value) {
95                 newstring = xmalloc (strlen (string) + strlen (value) + 2);
96                 sprintf (newstring, "%s=%s", string, value);
97         } else {
98                 newstring = xstrdup (string);
99         }
100
101         /*
102          * Search for a '=' character within the string and if none is found
103          * just ignore the whole string.
104          */
105
106         cp = strchr (newstring, '=');
107         if (!cp) {
108                 free (newstring);
109                 return;
110         }
111
112         n = (size_t) (cp - newstring);
113
114         for (i = 0; i < newenvc; i++) {
115                 if (strncmp (newstring, newenvp[i], n) == 0 &&
116                     (newenvp[i][n] == '=' || newenvp[i][n] == '\0'))
117                         break;
118         }
119
120         if (i < newenvc) {
121                 free (newenvp[i]);
122                 newenvp[i] = newstring;
123                 return;
124         }
125
126         newenvp[newenvc++] = newstring;
127
128         /*
129          * Check whether newenvc is a multiple of NEWENVP_STEP.
130          * If so we have to resize the vector.
131          * the expression (newenvc & (NEWENVP_STEP - 1)) == 0
132          * is equal to    (newenvc %  NEWENVP_STEP) == 0
133          * as long as NEWENVP_STEP is a power of 2.
134          */
135
136         if ((newenvc & (NEWENVP_STEP - 1)) == 0) {
137                 char **__newenvp;
138                 size_t newsize;
139
140                 /*
141                  * If the resize operation succeds we can
142                  * happily go on, else print a message.
143                  */
144
145                 newsize = (newenvc + NEWENVP_STEP) * sizeof (char *);
146                 __newenvp = (char **) realloc (newenvp, newsize);
147
148                 if (__newenvp) {
149                         /*
150                          * If this is our current environment, update
151                          * environ so that it doesn't point to some
152                          * free memory area (realloc() could move it).
153                          */
154                         if (environ == newenvp)
155                                 environ = __newenvp;
156                         newenvp = __newenvp;
157                 } else {
158                         fputs (_("Environment overflow\n"), stderr);
159                         free (newenvp[--newenvc]);
160                 }
161         }
162
163         /*
164          * The last entry of newenvp must be NULL
165          */
166
167         newenvp[newenvc] = NULL;
168 }
169
170
171 /*
172  * set_env - copy command line arguments into the environment
173  */
174 void set_env (int argc, char *const *argv)
175 {
176         int noname = 1;
177         char variable[1024];
178         char *cp;
179
180         for (; argc > 0; argc--, argv++) {
181                 if (strlen (*argv) >= sizeof variable)
182                         continue;       /* ignore long entries */
183
184                 if (!(cp = strchr (*argv, '='))) {
185                         snprintf (variable, sizeof variable, "L%d", noname++);
186                         addenv (variable, *argv);
187                 } else {
188                         const char **p;
189
190                         for (p = forbid; *p; p++)
191                                 if (strncmp (*argv, *p, strlen (*p)) == 0)
192                                         break;
193
194                         if (*p) {
195                                 strncpy (variable, *argv, cp - *argv);
196                                 variable[cp - *argv] = '\0';
197                                 printf (_("You may not change $%s\n"),
198                                         variable);
199                                 continue;
200                         }
201
202                         addenv (*argv, NULL);
203                 }
204         }
205 }
206
207 /*
208  * sanitize_env - remove some nasty environment variables
209  * If you fall into a total paranoia, you should call this
210  * function for any root-setuid program or anything the user
211  * might change the environment with. 99% useless as almost
212  * all modern Unixes will handle setuid executables properly,
213  * but... I feel better with that silly precaution. -j.
214  */
215
216 void sanitize_env (void)
217 {
218         char **envp = environ;
219         const char **bad;
220         char **cur;
221         char **move;
222
223         for (cur = envp; *cur; cur++) {
224                 for (bad = forbid; *bad; bad++) {
225                         if (strncmp (*cur, *bad, strlen (*bad)) == 0) {
226                                 for (move = cur; *move; move++)
227                                         *move = *(move + 1);
228                                 cur--;
229                                 break;
230                         }
231                 }
232         }
233
234         for (cur = envp; *cur; cur++) {
235                 for (bad = noslash; *bad; bad++) {
236                         if (strncmp (*cur, *bad, strlen (*bad)) != 0)
237                                 continue;
238                         if (!strchr (*cur, '/'))
239                                 continue;       /* OK */
240                         for (move = cur; *move; move++)
241                                 *move = *(move + 1);
242                         cur--;
243                         break;
244                 }
245         }
246 }