]> git.ipfire.org Git - thirdparty/glibc.git/blame - locale/findlocale.c
Avoid unsafe loc_name type casts with additional variable
[thirdparty/glibc.git] / locale / findlocale.c
CommitLineData
b168057a 1/* Copyright (C) 1996-2015 Free Software Foundation, Inc.
e4cf5070 2 This file is part of the GNU C Library.
4b10dd6c 3 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
7a12c6bb 4
e4cf5070 5 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
7a12c6bb 9
e4cf5070
UD
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41bdb6e2 13 Lesser General Public License for more details.
7a12c6bb 14
41bdb6e2 15 You should have received a copy of the GNU Lesser General Public
59ba27a6
PE
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
7a12c6bb 18
e7f21fa6 19#include <assert.h>
4e8f95a0 20#include <errno.h>
7a12c6bb
RM
21#include <locale.h>
22#include <stdlib.h>
23#include <string.h>
3081378b 24#include <unistd.h>
72c74375
UD
25#ifdef _POSIX_MAPPED_FILES
26# include <sys/mman.h>
27#endif
7a12c6bb
RM
28
29#include "localeinfo.h"
e7f21fa6 30#include "../iconv/gconv_charset.h"
dd9423a6 31#include "../iconv/gconv_int.h"
7a12c6bb
RM
32
33
9a411bf5
RM
34#ifdef NL_CURRENT_INDIRECT
35# define DEFINE_CATEGORY(category, category_name, items, a) \
f095bb72 36extern struct __locale_data _nl_C_##category; \
9a411bf5
RM
37weak_extern (_nl_C_##category)
38# include "categories.def"
39# undef DEFINE_CATEGORY
40
41/* Array indexed by category of pointers to _nl_C_CATEGORY slots.
42 Elements are zero for categories whose data is never used. */
f095bb72 43struct __locale_data *const _nl_C[] attribute_hidden =
9a411bf5
RM
44 {
45# define DEFINE_CATEGORY(category, category_name, items, a) \
46 [category] = &_nl_C_##category,
47# include "categories.def"
48# undef DEFINE_CATEGORY
49 };
30c14c31
RM
50#else
51# define _nl_C (_nl_C_locobj.__locales)
52#endif
7a12c6bb
RM
53
54
55/* For each category we keep a list of records for the locale files
56 which are somehow addressed. */
5746ef6f 57struct loaded_l10nfile *_nl_locale_file_list[__LC_LAST];
7a12c6bb 58
cb09a2cd
RM
59const char _nl_default_locale_path[] attribute_hidden = LOCALEDIR;
60
4e8f95a0
FW
61/* Checks if the name is actually present, that is, not NULL and not
62 empty. */
63static inline int
64name_present (const char *name)
65{
66 return name != NULL && name[0] != '\0';
67}
68
69/* Checks that the locale name neither extremely long, nor contains a
70 ".." path component (to prevent directory traversal). */
71static inline int
72valid_locale_name (const char *name)
73{
74 /* Not set. */
75 size_t namelen = strlen (name);
76 /* Name too long. The limit is arbitrary and prevents stack overflow
77 issues later. */
78 if (__glibc_unlikely (namelen > 255))
79 return 0;
80 /* Directory traversal attempt. */
81 static const char slashdot[4] = {'/', '.', '.', '/'};
9975e3d3
JM
82 if (__glibc_unlikely (__memmem (name, namelen,
83 slashdot, sizeof (slashdot)) != NULL))
4e8f95a0
FW
84 return 0;
85 if (namelen == 2 && __glibc_unlikely (name[0] == '.' && name [1] == '.'))
86 return 0;
87 if (namelen >= 3
88 && __glibc_unlikely (((name[0] == '.'
89 && name[1] == '.'
90 && name[2] == '/')
91 || (name[namelen - 3] == '/'
92 && name[namelen - 2] == '.'
93 && name[namelen - 1] == '.'))))
94 return 0;
95 /* If there is a slash in the name, it must start with one. */
96 if (__glibc_unlikely (memchr (name, '/', namelen) != NULL) && name[0] != '/')
97 return 0;
98 return 1;
99}
7a12c6bb 100
f095bb72 101struct __locale_data *
cb09a2cd 102internal_function
7a12c6bb 103_nl_find_locale (const char *locale_path, size_t locale_path_len,
c84142e8 104 int category, const char **name)
7a12c6bb
RM
105{
106 int mask;
107 /* Name of the locale for this category. */
e7f07af5 108 const char *cloc_name = *name;
7a12c6bb
RM
109 const char *language;
110 const char *modifier;
111 const char *territory;
112 const char *codeset;
113 const char *normalized_codeset;
7a12c6bb
RM
114 struct loaded_l10nfile *locale_file;
115
e7f07af5 116 if (cloc_name[0] == '\0')
7a12c6bb
RM
117 {
118 /* The user decides which locale to use by setting environment
119 variables. */
e7f07af5
AO
120 cloc_name = getenv ("LC_ALL");
121 if (!name_present (cloc_name))
122 cloc_name = getenv (_nl_category_names.str
123 + _nl_category_name_idxs[category]);
124 if (!name_present (cloc_name))
125 cloc_name = getenv ("LANG");
126 if (!name_present (cloc_name))
127 cloc_name = _nl_C_name;
7a12c6bb
RM
128 }
129
4e8f95a0
FW
130 /* We used to fall back to the C locale if the name contains a slash
131 character '/', but we now check for directory traversal in
132 valid_locale_name, so this is no longer necessary. */
63336471 133
e7f07af5
AO
134 if (__builtin_expect (strcmp (cloc_name, _nl_C_name), 1) == 0
135 || __builtin_expect (strcmp (cloc_name, _nl_POSIX_name), 1) == 0)
7a12c6bb
RM
136 {
137 /* We need not load anything. The needed data is contained in
138 the library itself. */
e7f07af5 139 *name = _nl_C_name;
7a12c6bb
RM
140 return _nl_C[category];
141 }
e7f07af5 142 else if (!valid_locale_name (cloc_name))
4e8f95a0
FW
143 {
144 __set_errno (EINVAL);
145 return NULL;
146 }
147
e7f07af5 148 *name = cloc_name;
7a12c6bb 149
cb09a2cd
RM
150 /* We really have to load some data. First we try the archive,
151 but only if there was no LOCPATH environment variable specified. */
a1ffb40e 152 if (__glibc_likely (locale_path == NULL))
cb09a2cd 153 {
f095bb72
UD
154 struct __locale_data *data
155 = _nl_load_locale_from_archive (category, name);
a1ffb40e 156 if (__glibc_likely (data != NULL))
cb09a2cd
RM
157 return data;
158
0d822a01
AO
159 /* Nothing in the archive with the given name. Expanding it as
160 an alias and retry. */
e7f07af5
AO
161 cloc_name = _nl_expand_alias (*name);
162 if (cloc_name != NULL)
0d822a01 163 {
e7f07af5 164 data = _nl_load_locale_from_archive (category, &cloc_name);
0d822a01
AO
165 if (__builtin_expect (data != NULL, 1))
166 return data;
167 }
168
cb09a2cd
RM
169 /* Nothing in the archive. Set the default path to search below. */
170 locale_path = _nl_default_locale_path;
171 locale_path_len = sizeof _nl_default_locale_path;
172 }
0d822a01
AO
173 else
174 /* We really have to load some data. First see whether the name is
175 an alias. Please note that this makes it impossible to have "C"
176 or "POSIX" as aliases. */
e7f07af5 177 cloc_name = _nl_expand_alias (*name);
cb09a2cd 178
e7f07af5 179 if (cloc_name == NULL)
7a12c6bb 180 /* It is no alias. */
e7f07af5 181 cloc_name = *name;
7a12c6bb
RM
182
183 /* Make a writable copy of the locale name. */
e7f07af5 184 char *loc_name = strdupa (cloc_name);
7a12c6bb
RM
185
186 /* LOCALE can consist of up to four recognized parts for the XPG syntax:
187
188 language[_territory[.codeset]][@modifier]
189
7a12c6bb
RM
190 Beside the first all of them are allowed to be missing. If the
191 full specified locale is not found, the less specific one are
cb09a2cd 192 looked for. The various part will be stripped off according to
7a12c6bb 193 the following order:
e155c801
UD
194 (1) codeset
195 (2) normalized codeset
196 (3) territory
197 (4) modifier
7a12c6bb
RM
198 */
199 mask = _nl_explode_name (loc_name, &language, &modifier, &territory,
e155c801 200 &codeset, &normalized_codeset);
4f031072
UD
201 if (mask == -1)
202 /* Memory allocate problem. */
203 return NULL;
7a12c6bb
RM
204
205 /* If exactly this locale was already asked for we have an entry with
206 the complete name. */
5746ef6f 207 locale_file = _nl_make_l10nflist (&_nl_locale_file_list[category],
7a12c6bb
RM
208 locale_path, locale_path_len, mask,
209 language, territory, codeset,
e155c801 210 normalized_codeset, modifier,
9446614c
UD
211 _nl_category_names.str
212 + _nl_category_name_idxs[category], 0);
7a12c6bb
RM
213
214 if (locale_file == NULL)
215 {
216 /* Find status record for addressed locale file. We have to search
217 through all directories in the locale path. */
5746ef6f 218 locale_file = _nl_make_l10nflist (&_nl_locale_file_list[category],
7a12c6bb
RM
219 locale_path, locale_path_len, mask,
220 language, territory, codeset,
e155c801 221 normalized_codeset, modifier,
9446614c
UD
222 _nl_category_names.str
223 + _nl_category_name_idxs[category], 1);
7a12c6bb
RM
224 if (locale_file == NULL)
225 /* This means we are out of core. */
226 return NULL;
227 }
7a12c6bb 228
727211c4
UD
229 /* The space for normalized_codeset is dynamically allocated. Free it. */
230 if (mask & XPG_NORM_CODESET)
231 free ((void *) normalized_codeset);
232
7a12c6bb
RM
233 if (locale_file->decided == 0)
234 _nl_load_locale (locale_file, category);
235
236 if (locale_file->data == NULL)
237 {
238 int cnt;
239 for (cnt = 0; locale_file->successor[cnt] != NULL; ++cnt)
240 {
241 if (locale_file->successor[cnt]->decided == 0)
242 _nl_load_locale (locale_file->successor[cnt], category);
243 if (locale_file->successor[cnt]->data != NULL)
244 break;
245 }
246 /* Move the entry we found (or NULL) to the first place of
247 successors. */
248 locale_file->successor[0] = locale_file->successor[cnt];
249 locale_file = locale_file->successor[cnt];
7a12c6bb 250
3a31f6f4
UD
251 if (locale_file == NULL)
252 return NULL;
253 }
7a12c6bb 254
e7f21fa6
UD
255 /* The LC_CTYPE category allows to check whether a locale is really
256 usable. If the locale name contains a charset name and the
257 charset name used in the locale (present in the LC_CTYPE data) is
258 not the same (after resolving aliases etc) we reject the locale
259 since using it would irritate users expecting the charset named
260 in the locale name. */
261 if (codeset != NULL)
262 {
263 /* Get the codeset information from the locale file. */
264 static const int codeset_idx[] =
265 {
266 [__LC_CTYPE] = _NL_ITEM_INDEX (CODESET),
267 [__LC_NUMERIC] = _NL_ITEM_INDEX (_NL_NUMERIC_CODESET),
268 [__LC_TIME] = _NL_ITEM_INDEX (_NL_TIME_CODESET),
269 [__LC_COLLATE] = _NL_ITEM_INDEX (_NL_COLLATE_CODESET),
270 [__LC_MONETARY] = _NL_ITEM_INDEX (_NL_MONETARY_CODESET),
271 [__LC_MESSAGES] = _NL_ITEM_INDEX (_NL_MESSAGES_CODESET),
272 [__LC_PAPER] = _NL_ITEM_INDEX (_NL_PAPER_CODESET),
273 [__LC_NAME] = _NL_ITEM_INDEX (_NL_NAME_CODESET),
274 [__LC_ADDRESS] = _NL_ITEM_INDEX (_NL_ADDRESS_CODESET),
275 [__LC_TELEPHONE] = _NL_ITEM_INDEX (_NL_TELEPHONE_CODESET),
276 [__LC_MEASUREMENT] = _NL_ITEM_INDEX (_NL_MEASUREMENT_CODESET),
277 [__LC_IDENTIFICATION] = _NL_ITEM_INDEX (_NL_IDENTIFICATION_CODESET)
278 };
f095bb72 279 const struct __locale_data *data;
e7f21fa6
UD
280 const char *locale_codeset;
281 char *clocale_codeset;
282 char *ccodeset;
283
f095bb72 284 data = (const struct __locale_data *) locale_file->data;
e7f21fa6
UD
285 locale_codeset =
286 (const char *) data->values[codeset_idx[category]].string;
287 assert (locale_codeset != NULL);
288 /* Note the length of the allocated memory: +3 for up to two slashes
289 and the NUL byte. */
290 clocale_codeset = (char *) alloca (strlen (locale_codeset) + 3);
291 strip (clocale_codeset, locale_codeset);
292
293 ccodeset = (char *) alloca (strlen (codeset) + 3);
294 strip (ccodeset, codeset);
295
9a018f6c
UD
296 if (__gconv_compare_alias (upstr (ccodeset, ccodeset),
297 upstr (clocale_codeset,
298 clocale_codeset)) != 0)
e7f21fa6
UD
299 /* The codesets are not identical, don't use the locale. */
300 return NULL;
301 }
302
7a12c6bb
RM
303 /* Determine the locale name for which loading succeeded. This
304 information comes from the file name. The form is
036cc82f 305 <path>/<locale>/LC_foo. We must extract the <locale> part. */
f095bb72 306 if (((const struct __locale_data *) locale_file->data)->name == NULL)
7a12c6bb 307 {
036cc82f 308 char *cp, *endp;
7a12c6bb
RM
309
310 endp = strrchr (locale_file->filename, '/');
311 cp = endp - 1;
312 while (cp[-1] != '/')
313 --cp;
f095bb72
UD
314 ((struct __locale_data *) locale_file->data)->name
315 = __strndup (cp, endp - cp);
7a12c6bb 316 }
7a12c6bb 317
323fb88d 318 /* Determine whether the user wants transliteration or not. */
5f078c32
UD
319 if (modifier != NULL
320 && __strcasecmp_l (modifier, "TRANSLIT", _nl_C_locobj_ptr) == 0)
f095bb72 321 ((struct __locale_data *) locale_file->data)->use_translit = 1;
323fb88d 322
c84142e8 323 /* Increment the usage count. */
f095bb72 324 if (((const struct __locale_data *) locale_file->data)->usage_count
a5a0310d 325 < MAX_USAGE_COUNT)
f095bb72 326 ++((struct __locale_data *) locale_file->data)->usage_count;
c84142e8 327
f095bb72 328 return (struct __locale_data *) locale_file->data;
7a12c6bb 329}
c84142e8
UD
330
331
332/* Calling this function assumes the lock for handling global locale data
333 is acquired. */
334void
cb09a2cd 335internal_function
f095bb72 336_nl_remove_locale (int locale, struct __locale_data *data)
c84142e8
UD
337{
338 if (--data->usage_count == 0)
339 {
0f283ffc 340 if (data->alloc != ld_archive)
c84142e8 341 {
0f283ffc
RM
342 /* First search the entry in the list of loaded files. */
343 struct loaded_l10nfile *ptr = _nl_locale_file_list[locale];
344
345 /* Search for the entry. It must be in the list. Otherwise it
346 is a bug and we crash badly. */
f095bb72 347 while ((struct __locale_data *) ptr->data != data)
0f283ffc
RM
348 ptr = ptr->next;
349
350 /* Mark the data as not available anymore. So when the data has
351 to be used again it is reloaded. */
352 ptr->decided = 0;
353 ptr->data = NULL;
c84142e8 354 }
c84142e8 355
0f283ffc
RM
356 /* This does the real work. */
357 _nl_unload_locale (data);
c84142e8
UD
358 }
359}