1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <stdlib.h>
27 #include <errno.h>
28 #include <sys/types.h>
29 #include <dlfcn.h>
30 #include <link.h>
31 #include <sys/utsname.h>
32 #include <ctype.h>
33 #include <strings.h>
34 #include <string.h>
35 #include <idn/api.h>
36 #include <idn/version.h>
37 #include "ace.h"
38
39
40 void *
_icv_open()41 _icv_open()
42 {
43 ace_state_t *cd;
44
45 cd = (ace_state_t *)calloc(1, sizeof(ace_state_t));
46 if (cd == (ace_state_t *)NULL) {
47 errno = ENOMEM;
48 return ((void *)-1);
49 }
50
51 cd->libidnkit = dlopen(ICV_LIBIDNKITPATH, RTLD_LAZY);
52 if (cd->libidnkit == (void *)NULL) {
53 free((void *)cd);
54 errno = EINVAL;
55 return ((void *)-1);
56 }
57
58 cd->idn_function = (idn_result_t(*)(int, const char *, char *,
59 #if defined(ICV_ACE_TO_UTF8)
60 size_t))dlsym(cd->libidnkit, "idn_decodename");
61 #else
62 size_t))dlsym(cd->libidnkit, "idn_encodename");
63 #endif /* defined(ICV_ACE_TO_UTF8) */
64 if (cd->idn_function ==
65 (idn_result_t(*)(int, const char *, char *, size_t))NULL) {
66 (void) dlclose(cd->libidnkit);
67 free((void *)cd);
68 errno = EINVAL;
69 return ((void *)-1);
70 }
71
72 cd->ib = (uchar_t *)malloc(_SYS_NMLN);
73 if (cd->ib == (uchar_t *)NULL) {
74 (void) dlclose(cd->libidnkit);
75 free((void *)cd);
76 errno = ENOMEM;
77 return ((void *)-1);
78 }
79
80 cd->ob = (uchar_t *)malloc(_SYS_NMLN);
81 if (cd->ob == (uchar_t *)NULL) {
82 (void) dlclose(cd->libidnkit);
83 free((void *)cd->ib);
84 free((void *)cd);
85 errno = ENOMEM;
86 return ((void *)-1);
87 }
88
89 cd->ibl = cd->obl = _SYS_NMLN;
90 cd->iblconsumed = cd->oblremaining = 0;
91
92 return ((void *)cd);
93 }
94
95
96 void
_icv_close(ace_state_t * cd)97 _icv_close(ace_state_t *cd)
98 {
99 if (! cd)
100 errno = EBADF;
101 else {
102 (void) dlclose(cd->libidnkit);
103 free((void *)cd->ib);
104 free((void *)cd->ob);
105 free((void *)cd);
106 }
107 }
108
109
110 size_t
_icv_iconv(ace_state_t * cd,char ** inbuf,size_t * inbufleft,char ** outbuf,size_t * outbufleft)111 _icv_iconv(ace_state_t *cd, char **inbuf, size_t *inbufleft, char **outbuf,
112 size_t *outbufleft)
113 {
114 size_t ret_val = 0;
115 uchar_t *ib;
116 uchar_t *ob;
117 uchar_t *ibtail;
118 uchar_t *obtail;
119 uchar_t *tmps;
120 idn_result_t idnres;
121 idn_action_t actions;
122 int i;
123
124
125 if (! cd) {
126 errno = EBADF;
127 return((size_t)-1);
128 }
129
130 /*
131 * We need an output buffer in pretty much anycase and so we check it
132 * here and issue E2BIG if there the output buffer isn't supplied
133 * properly.
134 */
135 if (!outbuf || !(*outbuf)) {
136 errno = E2BIG;
137 return ((size_t)-1);
138 }
139
140 ob = (uchar_t *)*outbuf;
141 obtail = ob + *outbufleft;
142
143 /*
144 * Always flush first any previously remaining output buffer at
145 * the conversion descriptor.
146 */
147 for (i = 0; i < cd->oblremaining; i++) {
148 if (ob >= obtail) {
149 errno = E2BIG;
150 cd->oblremaining -= i;
151 (void) memmove((void *)cd->ob,
152 (const void *)(cd->ob + i), cd->oblremaining);
153 ret_val = (size_t)-1;
154 goto ICV_ICONV_RETURN_TWO;
155 }
156 *ob++ = cd->ob[i];
157 }
158 cd->oblremaining = 0;
159
160 #ifdef IDNKIT_VERSION_LIBIDN
161
162 /* IDNkit v2 */
163
164 actions =
165 IDN_RTCONV
166 |IDN_PROHCHECK
167 |IDN_NFCCHECK
168 |IDN_PREFCHECK
169 |IDN_COMBCHECK
170 |IDN_CTXOLITECHECK
171 |IDN_BIDICHECK
172 |IDN_LOCALCHECK
173 |IDN_IDNCONV
174 |IDN_LENCHECK;
175
176 # if defined(ICV_ACE_TO_UTF8)
177 actions |= IDN_RTCHECK;
178 # else
179 actions |= IDN_MAP;
180 # endif
181
182 #else
183
184 /* IDNkit v1 */
185 actions =
186 IDN_DELIMMAP
187 |IDN_NAMEPREP
188 |IDN_IDNCONV
189 |IDN_ASCCHECK;
190
191 # if defined(ICV_ACE_TO_UTF8)
192 actions |= IDN_RTCHECK;
193 # else
194 actions |= IDN_LOCALMAP;
195 # endif
196
197 #endif
198
199 #if !defined(ICV_IDN_ALLOW_UNASSIGNED)
200 actions |= IDN_UNASCHECK;
201 #endif
202
203 /* Process reset request. */
204 if (!inbuf || !(*inbuf)) {
205 if (cd->iblconsumed > 0) {
206 if (cd->iblconsumed >= cd->ibl) {
207 cd->ibl += _SYS_NMLN;
208 tmps = (uchar_t *)realloc((void *)cd->ib,
209 cd->ibl);
210 if (tmps == (uchar_t *)NULL) {
211 /*
212 * We couldn't allocate any more;
213 * return with realloc()'s errno.
214 */
215 cd->ibl -= _SYS_NMLN;
216 ret_val = (size_t)-1;
217 goto ICV_ICONV_RETURN_TWO;
218 }
219 cd->ib = tmps;
220 }
221
222 *(cd->ib + cd->iblconsumed++) = '\0';
223
224 i = 0;
225 ICV_ICONV_LOOP_ONE:
226 idnres = (*(cd->idn_function))(actions,
227 (const char *)cd->ib, (char *)cd->ob,
228 cd->obl);
229 switch (idnres) {
230 case idn_success:
231 break;
232 case idn_buffer_overflow:
233 if (++i >= 2) {
234 errno = EILSEQ;
235 ret_val = (size_t)-1;
236 goto ICV_ICONV_RETURN_TWO;
237 }
238 cd->obl += _SYS_NMLN;
239 tmps = (uchar_t *)realloc((void *)cd->ob,
240 cd->obl);
241 if (tmps == (uchar_t *)NULL) {
242 /*
243 * We couldn't allocate any more;
244 * return with realloc()'s errno.
245 */
246 cd->obl -= _SYS_NMLN;
247 ret_val = (size_t)-1;
248 goto ICV_ICONV_RETURN_TWO;
249 }
250 cd->ob = tmps;
251 goto ICV_ICONV_LOOP_ONE;
252 default:
253 /*
254 * Anything else we just treat
255 * as illegal sequence error.
256 */
257 errno = EILSEQ;
258 ret_val = (size_t)-1;
259 goto ICV_ICONV_RETURN_TWO;
260 }
261
262 cd->iblconsumed = 0;
263
264 cd->oblremaining = strlen((const char *)cd->ob);
265 for (i = 0; i < cd->oblremaining; i++) {
266 if (ob >= obtail) {
267 errno = E2BIG;
268 cd->oblremaining -= i;
269 (void) memmove((void *)cd->ob,
270 (const void *)(cd->ob + i),
271 cd->oblremaining);
272 ret_val = (size_t)-1;
273 goto ICV_ICONV_RETURN_TWO;
274 }
275 *ob++ = cd->ob[i];
276 }
277 cd->oblremaining = 0;
278 }
279
280 ret_val = (size_t)0;
281 goto ICV_ICONV_RETURN_TWO;
282 }
283
284 ib = (uchar_t *)*inbuf;
285 ibtail = ib + *inbufleft;
286
287 while (ib < ibtail) {
288 /*
289 * We only use bare minimum single byte space class characters
290 * as delimiters between names.
291 */
292 if (isspace(*ib)) {
293 if (cd->iblconsumed > 0) {
294 if (cd->iblconsumed >= cd->ibl) {
295 cd->ibl += _SYS_NMLN;
296 tmps = (uchar_t *)realloc(
297 (void *)cd->ib, cd->ibl);
298 if (tmps == (uchar_t *)NULL) {
299 /*
300 * We couldn't allocate any
301 * more; return with
302 * realloc()'s errno.
303 */
304 cd->ibl -= _SYS_NMLN;
305 ret_val = (size_t)-1;
306 break;
307 }
308 cd->ib = tmps;
309 }
310 *(cd->ib + cd->iblconsumed) = '\0';
311 i = 0;
312 ICV_ICONV_LOOP:
313 idnres = (*(cd->idn_function))(actions,
314 (const char *)cd->ib, (char *)cd->ob,
315 cd->obl);
316 switch (idnres) {
317 case idn_success:
318 break;
319 case idn_buffer_overflow:
320 if (++i >= 2) {
321 errno = EILSEQ;
322 ret_val = (size_t)-1;
323 goto ICV_ICONV_RETURN;
324 }
325 cd->obl += _SYS_NMLN;
326 tmps = (uchar_t *)realloc(
327 (void *)cd->ob, cd->obl);
328 if (tmps == (uchar_t *)NULL) {
329 /*
330 * We couldn't allocate any
331 * more; return with
332 * realloc()'s errno.
333 */
334 cd->obl -= _SYS_NMLN;
335 ret_val = (size_t)-1;
336 goto ICV_ICONV_RETURN;
337 }
338 cd->ob = tmps;
339 goto ICV_ICONV_LOOP;
340 default:
341 /*
342 * Anything else we just treat
343 * as illegal sequence error.
344 */
345 errno = EILSEQ;
346 ret_val = (size_t)-1;
347 goto ICV_ICONV_RETURN;
348 }
349
350 cd->iblconsumed = 0;
351
352 cd->oblremaining = strlen((const char *)cd->ob);
353 for (i = 0; i < cd->oblremaining; i++) {
354 if (ob >= obtail) {
355 errno = E2BIG;
356 ret_val = (size_t)-1;
357 cd->oblremaining -= i;
358 (void) memmove((void *)cd->ob,
359 (const void *)(cd->ob + i),
360 cd->oblremaining);
361 goto ICV_ICONV_RETURN;
362 }
363 *ob++ = cd->ob[i];
364 }
365 cd->oblremaining = 0;
366 }
367 if (ob >= obtail) {
368 errno = E2BIG;
369 ret_val = (size_t)-1;
370 break;
371 }
372 *ob++ = *ib++;
373 } else {
374 if (cd->iblconsumed >= cd->ibl) {
375 cd->ibl += _SYS_NMLN;
376 tmps = (uchar_t *)realloc((void *)cd->ib,
377 cd->ibl);
378 if (tmps == (uchar_t *)NULL) {
379 /*
380 * We couldn't allocate any more;
381 * return with realloc()'s errno.
382 */
383 cd->ibl -= _SYS_NMLN;
384 ret_val = (size_t)-1;
385 break;
386 }
387 cd->ib = tmps;
388 }
389 *(cd->ib + cd->iblconsumed++) = *ib++;
390 }
391 } /* while (ib < ibtail) */
392
393 ICV_ICONV_RETURN:
394 *inbuf = (char *)ib;
395 *inbufleft = ibtail - ib;
396 ICV_ICONV_RETURN_TWO:
397 *outbuf = (char *)ob;
398 *outbufleft = obtail - ob;
399
400 return(ret_val);
401 }
402