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 * 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 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 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