1 /* $OpenBSD: rune.c,v 1.10 2022/07/27 20:00:11 guenther Exp $ */
2 /* $NetBSD: rune.c,v 1.26 2004/05/09 11:26:33 kleink Exp $ */
3
4 /*-
5 * Copyright (c)1999 Citrus Project,
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 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 /*-
31 * Copyright (c) 1993
32 * The Regents of the University of California. All rights reserved.
33 *
34 * This code is derived from software contributed to Berkeley by
35 * Paul Borman at Krystal Technologies.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 * 3. Neither the name of the University nor the names of its contributors
46 * may be used to endorse or promote products derived from this software
47 * without specific prior written permission.
48 *
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * SUCH DAMAGE.
60 */
61
62 #include <sys/types.h>
63 #include <sys/stat.h>
64 #include <assert.h>
65 #include <errno.h>
66 #include <stdint.h>
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <string.h>
70 #include <wchar.h>
71 #include "rune.h"
72 #include "rune_local.h"
73
74 #define SAFE_ADD(x, y) \
75 do { \
76 if ((x) > SIZE_MAX - (y)) \
77 return NULL; \
78 (x) += (y); \
79 } while (0);
80
81 static int readrange(_RuneLocale *, _RuneRange *, uint32_t, void *, FILE *);
82 static void _freeentry(_RuneRange *);
83
84 static int
readrange(_RuneLocale * rl,_RuneRange * rr,uint32_t nranges,void * lastp,FILE * fp)85 readrange(_RuneLocale *rl, _RuneRange *rr, uint32_t nranges, void *lastp,
86 FILE *fp)
87 {
88 uint32_t i;
89 _RuneEntry *re;
90 _FileRuneEntry fre;
91
92 re = (_RuneEntry *)rl->rl_variable;
93
94 rr->rr_nranges = nranges;
95 if (rr->rr_nranges == 0) {
96 rr->rr_rune_ranges = NULL;
97 return 0;
98 }
99
100 rr->rr_rune_ranges = re;
101 for (i = 0; i < rr->rr_nranges; i++) {
102 if ((void *)re >= lastp)
103 return -1;
104
105 if (fread(&fre, sizeof(fre), 1, fp) != 1)
106 return -1;
107
108 re->re_min = ntohl((uint32_t)fre.fre_min);
109 re->re_max = ntohl((uint32_t)fre.fre_max);
110 re->re_map = ntohl((uint32_t)fre.fre_map);
111 re++;
112 }
113 rl->rl_variable = re;
114 return 0;
115 }
116
117 static int
readentry(_RuneRange * rr,FILE * fp)118 readentry(_RuneRange *rr, FILE *fp)
119 {
120 _RuneEntry *re;
121 size_t l, i, j;
122 int error;
123
124 re = rr->rr_rune_ranges;
125 for (i = 0; i < rr->rr_nranges; i++) {
126 if (re[i].re_map != 0) {
127 re[i].re_rune_types = NULL;
128 continue;
129 }
130
131 if (re[i].re_max < re[i].re_min) {
132 error = EINVAL;
133 goto fail;
134 }
135
136 l = re[i].re_max - re[i].re_min + 1;
137 re[i].re_rune_types = calloc(l, sizeof(_RuneType));
138 if (!re[i].re_rune_types) {
139 error = ENOMEM;
140 goto fail;
141 }
142
143 if (fread(re[i].re_rune_types, sizeof(_RuneType), l, fp) != l)
144 goto fail2;
145
146 for (j = 0; j < l; j++)
147 re[i].re_rune_types[j] = ntohl(re[i].re_rune_types[j]);
148 }
149 return 0;
150
151 fail:
152 for (j = 0; j < i; j++) {
153 free(re[j].re_rune_types);
154 re[j].re_rune_types = NULL;
155 }
156 return error;
157 fail2:
158 for (j = 0; j <= i; j++) {
159 free(re[j].re_rune_types);
160 re[j].re_rune_types = NULL;
161 }
162 return errno;
163 }
164
165 /* XXX: temporary implementation */
166 static int
find_codeset(_RuneLocale * rl)167 find_codeset(_RuneLocale *rl)
168 {
169 char *top, *codeset, *tail, *ep;
170
171 if (rl->rl_variable == NULL)
172 return 0;
173
174 /* end of rl_variable region */
175 ep = (char *)rl->rl_variable;
176 ep += rl->rl_variable_len;
177 rl->rl_codeset = NULL;
178 if (!(top = strstr(rl->rl_variable, _RUNE_CODESET)))
179 return 0;
180 tail = strpbrk(top, " \t");
181 codeset = top + sizeof(_RUNE_CODESET) - 1;
182 if (tail) {
183 *top = *tail;
184 *tail = '\0';
185 rl->rl_codeset = strdup(codeset);
186 strlcpy(top + 1, tail + 1, (unsigned)(ep - (top + 1)));
187 } else {
188 *top = '\0';
189 rl->rl_codeset = strdup(codeset);
190 }
191 return (rl->rl_codeset == NULL);
192 }
193
194 void
_freeentry(_RuneRange * rr)195 _freeentry(_RuneRange *rr)
196 {
197 _RuneEntry *re;
198 uint32_t i;
199
200 re = rr->rr_rune_ranges;
201 for (i = 0; i < rr->rr_nranges; i++) {
202 free(re[i].re_rune_types);
203 re[i].re_rune_types = NULL;
204 }
205 }
206
207
208 _RuneLocale *
_Read_RuneMagi(FILE * fp)209 _Read_RuneMagi(FILE *fp)
210 {
211 /* file */
212 _FileRuneLocale frl;
213 /* host data */
214 char *hostdata;
215 size_t hostdatalen;
216 void *lastp;
217 _RuneLocale *rl;
218 struct stat sb;
219 int x;
220 uint32_t runetype_nranges, maplower_nranges, mapupper_nranges, var_len;
221
222 if (fstat(fileno(fp), &sb) == -1)
223 return NULL;
224
225 if (sb.st_size < sizeof(_FileRuneLocale))
226 return NULL;
227 /* XXX more validation? */
228
229 /* Someone might have read the magic number once already */
230 rewind(fp);
231
232 if (fread(&frl, sizeof(frl), 1, fp) != 1)
233 return NULL;
234 if (memcmp(frl.frl_magic, _RUNE_MAGIC_1, sizeof(frl.frl_magic)))
235 return NULL;
236
237 runetype_nranges = ntohl(frl.frl_runetype_ext.frr_nranges);
238 maplower_nranges = ntohl(frl.frl_maplower_ext.frr_nranges);
239 mapupper_nranges = ntohl(frl.frl_mapupper_ext.frr_nranges);
240 var_len = ntohl((uint32_t)frl.frl_variable_len);
241
242 #if SIZE_MAX <= UINT32_MAX
243 if (runetype_nranges > SIZE_MAX / sizeof(_RuneEntry) ||
244 maplower_nranges > SIZE_MAX / sizeof(_RuneEntry) ||
245 mapupper_nranges > SIZE_MAX / sizeof(_RuneEntry))
246 return NULL;
247 #endif
248
249 if (var_len > INT32_MAX)
250 return NULL;
251
252 hostdatalen = sizeof(*rl);
253 SAFE_ADD(hostdatalen, var_len);
254 SAFE_ADD(hostdatalen, runetype_nranges * sizeof(_RuneEntry));
255 SAFE_ADD(hostdatalen, maplower_nranges * sizeof(_RuneEntry));
256 SAFE_ADD(hostdatalen, mapupper_nranges * sizeof(_RuneEntry));
257
258 if ((hostdata = calloc(hostdatalen, 1)) == NULL)
259 return NULL;
260 lastp = hostdata + hostdatalen;
261
262 rl = (_RuneLocale *)hostdata;
263 rl->rl_variable = rl + 1;
264
265 rl->rl_variable_len = ntohl((uint32_t)frl.frl_variable_len);
266
267 for (x = 0; x < _CACHED_RUNES; ++x) {
268 rl->rl_runetype[x] = ntohl(frl.frl_runetype[x]);
269
270 /* XXX assumes rune_t = uint32_t */
271 rl->rl_maplower[x] = ntohl((uint32_t)frl.frl_maplower[x]);
272 rl->rl_mapupper[x] = ntohl((uint32_t)frl.frl_mapupper[x]);
273 }
274
275 if (readrange(rl, &rl->rl_runetype_ext, runetype_nranges, lastp, fp) ||
276 readrange(rl, &rl->rl_maplower_ext, maplower_nranges, lastp, fp) ||
277 readrange(rl, &rl->rl_mapupper_ext, mapupper_nranges, lastp, fp))
278 goto err;
279
280 if (readentry(&rl->rl_runetype_ext, fp) != 0)
281 goto err;
282
283 if ((uint8_t *)rl->rl_variable + rl->rl_variable_len >
284 (uint8_t *)lastp)
285 goto rune_err;
286
287 if (rl->rl_variable_len == 0)
288 rl->rl_variable = NULL;
289 else if (fread(rl->rl_variable, rl->rl_variable_len, 1, fp) != 1)
290 goto rune_err;
291 if (find_codeset(rl))
292 goto rune_err;
293
294 /*
295 * error if we have junk at the tail
296 */
297 if (ftello(fp) != sb.st_size)
298 goto rune_err;
299
300 return(rl);
301 rune_err:
302 _freeentry(&rl->rl_runetype_ext);
303 err:
304 free(hostdata);
305 return NULL;
306 }
307