netwerk/dns/nameprep.c

Wed, 31 Dec 2014 06:55:46 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:46 +0100
changeset 1
ca08bd8f51b2
permissions
-rw-r--r--

Added tag TORBROWSER_REPLICA for changeset 6474c204b198

michael@0 1 /*
michael@0 2 * Copyright (c) 2001,2002 Japan Network Information Center.
michael@0 3 * All rights reserved.
michael@0 4 *
michael@0 5 * By using this file, you agree to the terms and conditions set forth bellow.
michael@0 6 *
michael@0 7 * LICENSE TERMS AND CONDITIONS
michael@0 8 *
michael@0 9 * The following License Terms and Conditions apply, unless a different
michael@0 10 * license is obtained from Japan Network Information Center ("JPNIC"),
michael@0 11 * a Japanese association, Kokusai-Kougyou-Kanda Bldg 6F, 2-3-4 Uchi-Kanda,
michael@0 12 * Chiyoda-ku, Tokyo 101-0047, Japan.
michael@0 13 *
michael@0 14 * 1. Use, Modification and Redistribution (including distribution of any
michael@0 15 * modified or derived work) in source and/or binary forms is permitted
michael@0 16 * under this License Terms and Conditions.
michael@0 17 *
michael@0 18 * 2. Redistribution of source code must retain the copyright notices as they
michael@0 19 * appear in each source code file, this License Terms and Conditions.
michael@0 20 *
michael@0 21 * 3. Redistribution in binary form must reproduce the Copyright Notice,
michael@0 22 * this License Terms and Conditions, in the documentation and/or other
michael@0 23 * materials provided with the distribution. For the purposes of binary
michael@0 24 * distribution the "Copyright Notice" refers to the following language:
michael@0 25 * "Copyright (c) 2000-2002 Japan Network Information Center. All rights reserved."
michael@0 26 *
michael@0 27 * 4. The name of JPNIC may not be used to endorse or promote products
michael@0 28 * derived from this Software without specific prior written approval of
michael@0 29 * JPNIC.
michael@0 30 *
michael@0 31 * 5. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY JPNIC
michael@0 32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
michael@0 33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
michael@0 34 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JPNIC BE LIABLE
michael@0 35 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
michael@0 36 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
michael@0 37 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
michael@0 38 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
michael@0 39 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
michael@0 40 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
michael@0 41 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
michael@0 42 */
michael@0 43
michael@0 44
michael@0 45 #include <stdlib.h>
michael@0 46 #include <string.h>
michael@0 47
michael@0 48 #include "nsIDNKitInterface.h"
michael@0 49
michael@0 50 #define UCS_MAX 0x7fffffff
michael@0 51 #define UNICODE_MAX 0x10ffff
michael@0 52
michael@0 53
michael@0 54 /*
michael@0 55 * Load NAMEPREP compiled tables.
michael@0 56 */
michael@0 57 #include "nameprepdata.c"
michael@0 58
michael@0 59 /*
michael@0 60 * Define mapping/checking functions for each version of the draft.
michael@0 61 */
michael@0 62
michael@0 63 #define VERSION id11
michael@0 64 #include "nameprep_template.c"
michael@0 65 #undef VERSION
michael@0 66
michael@0 67 typedef const char *(*nameprep_mapproc)(uint32_t v);
michael@0 68 typedef int (*nameprep_checkproc)(uint32_t v);
michael@0 69 typedef idn_biditype_t (*nameprep_biditypeproc)(uint32_t v);
michael@0 70
michael@0 71 static struct idn_nameprep {
michael@0 72 char *version;
michael@0 73 nameprep_mapproc map_proc;
michael@0 74 nameprep_checkproc prohibited_proc;
michael@0 75 nameprep_checkproc unassigned_proc;
michael@0 76 nameprep_biditypeproc biditype_proc;
michael@0 77 } nameprep_versions[] = {
michael@0 78 #define MAKE_NAMEPREP_HANDLE(version, id) \
michael@0 79 { version, \
michael@0 80 compose_sym2(nameprep_map_, id), \
michael@0 81 compose_sym2(nameprep_prohibited_, id), \
michael@0 82 compose_sym2(nameprep_unassigned_, id), \
michael@0 83 compose_sym2(nameprep_biditype_, id), }
michael@0 84 MAKE_NAMEPREP_HANDLE("nameprep-11", id11),
michael@0 85 { NULL, NULL, NULL, NULL, NULL },
michael@0 86 };
michael@0 87
michael@0 88 static idn_result_t idn_nameprep_check(nameprep_checkproc proc,
michael@0 89 const uint32_t *str,
michael@0 90 const uint32_t **found);
michael@0 91
michael@0 92 idn_result_t
michael@0 93 idn_nameprep_create(const char *version, idn_nameprep_t *handlep) {
michael@0 94 idn_nameprep_t handle;
michael@0 95
michael@0 96 assert(handlep != NULL);
michael@0 97
michael@0 98 TRACE(("idn_nameprep_create(version=%-.50s)\n",
michael@0 99 version == NULL ? "<NULL>" : version));
michael@0 100
michael@0 101 if (version == NULL)
michael@0 102 version = IDN_NAMEPREP_CURRENT;
michael@0 103
michael@0 104 /*
michael@0 105 * Lookup table for the specified version. Since the number of
michael@0 106 * versions won't be large (I don't want see draft-23 or such :-),
michael@0 107 * simple linear search is OK.
michael@0 108 */
michael@0 109 for (handle = nameprep_versions; handle->version != NULL; handle++) {
michael@0 110 if (strcmp(handle->version, version) == 0) {
michael@0 111 *handlep = handle;
michael@0 112 return (idn_success);
michael@0 113 }
michael@0 114 }
michael@0 115 return (idn_notfound);
michael@0 116 }
michael@0 117
michael@0 118 void
michael@0 119 idn_nameprep_destroy(idn_nameprep_t handle) {
michael@0 120 assert(handle != NULL);
michael@0 121
michael@0 122 TRACE(("idn_nameprep_destroy()\n"));
michael@0 123
michael@0 124 /* Nothing to do. */
michael@0 125 }
michael@0 126
michael@0 127 idn_result_t
michael@0 128 idn_nameprep_map(idn_nameprep_t handle, const uint32_t *from,
michael@0 129 uint32_t *to, size_t tolen) {
michael@0 130 assert(handle != NULL && from != NULL && to != NULL);
michael@0 131
michael@0 132 TRACE(("idn_nameprep_map(ctx=%s, from=\"%s\")\n",
michael@0 133 handle->version, idn__debug_ucs4xstring(from, 50)));
michael@0 134
michael@0 135 while (*from != '\0') {
michael@0 136 uint32_t v = *from;
michael@0 137 const char *mapped;
michael@0 138
michael@0 139 if (v > UCS_MAX) {
michael@0 140 /* This cannot happen, but just in case.. */
michael@0 141 return (idn_invalid_codepoint);
michael@0 142 } else if (v > UNICODE_MAX) {
michael@0 143 /* No mapping is possible. */
michael@0 144 mapped = NULL;
michael@0 145 } else {
michael@0 146 /* Try mapping. */
michael@0 147 mapped = (*handle->map_proc)(v);
michael@0 148 }
michael@0 149
michael@0 150 if (mapped == NULL) {
michael@0 151 /* No mapping. Just copy verbatim. */
michael@0 152 if (tolen < 1)
michael@0 153 return (idn_buffer_overflow);
michael@0 154 *to++ = v;
michael@0 155 tolen--;
michael@0 156 } else {
michael@0 157 const unsigned char *mappeddata;
michael@0 158 size_t mappedlen;
michael@0 159
michael@0 160 mappeddata = (const unsigned char *)mapped + 1;
michael@0 161 mappedlen = *mapped;
michael@0 162
michael@0 163 if (tolen < (mappedlen + 3) / 4)
michael@0 164 return (idn_buffer_overflow);
michael@0 165 tolen -= (mappedlen + 3) / 4;
michael@0 166 while (mappedlen >= 4) {
michael@0 167 *to = *mappeddata++;
michael@0 168 *to |= *mappeddata++ << 8;
michael@0 169 *to |= *mappeddata++ << 16;
michael@0 170 *to |= *mappeddata++ << 24;
michael@0 171 mappedlen -= 4;
michael@0 172 to++;
michael@0 173 }
michael@0 174 if (mappedlen > 0) {
michael@0 175 *to = *mappeddata++;
michael@0 176 *to |= (mappedlen >= 2) ?
michael@0 177 *mappeddata++ << 8: 0;
michael@0 178 *to |= (mappedlen >= 3) ?
michael@0 179 *mappeddata++ << 16: 0;
michael@0 180 to++;
michael@0 181 }
michael@0 182 }
michael@0 183 from++;
michael@0 184 }
michael@0 185 if (tolen == 0)
michael@0 186 return (idn_buffer_overflow);
michael@0 187 *to = '\0';
michael@0 188 return (idn_success);
michael@0 189 }
michael@0 190
michael@0 191 idn_result_t
michael@0 192 idn_nameprep_isprohibited(idn_nameprep_t handle, const uint32_t *str,
michael@0 193 const uint32_t **found) {
michael@0 194 assert(handle != NULL && str != NULL && found != NULL);
michael@0 195
michael@0 196 TRACE(("idn_nameprep_isprohibited(ctx=%s, str=\"%s\")\n",
michael@0 197 handle->version, idn__debug_ucs4xstring(str, 50)));
michael@0 198
michael@0 199 return (idn_nameprep_check(handle->prohibited_proc, str, found));
michael@0 200 }
michael@0 201
michael@0 202 idn_result_t
michael@0 203 idn_nameprep_isunassigned(idn_nameprep_t handle, const uint32_t *str,
michael@0 204 const uint32_t **found) {
michael@0 205 assert(handle != NULL && str != NULL && found != NULL);
michael@0 206
michael@0 207 TRACE(("idn_nameprep_isunassigned(handle->version, str=\"%s\")\n",
michael@0 208 handle->version, idn__debug_ucs4xstring(str, 50)));
michael@0 209
michael@0 210 return (idn_nameprep_check(handle->unassigned_proc, str, found));
michael@0 211 }
michael@0 212
michael@0 213 static idn_result_t
michael@0 214 idn_nameprep_check(nameprep_checkproc proc, const uint32_t *str,
michael@0 215 const uint32_t **found) {
michael@0 216 uint32_t v;
michael@0 217
michael@0 218 while (*str != '\0') {
michael@0 219 v = *str;
michael@0 220
michael@0 221 if (v > UCS_MAX) {
michael@0 222 /* This cannot happen, but just in case.. */
michael@0 223 return (idn_invalid_codepoint);
michael@0 224 } else if (v > UNICODE_MAX) {
michael@0 225 /* It is invalid.. */
michael@0 226 *found = str;
michael@0 227 return (idn_success);
michael@0 228 } else if ((*proc)(v)) {
michael@0 229 *found = str;
michael@0 230 return (idn_success);
michael@0 231 }
michael@0 232 str++;
michael@0 233 }
michael@0 234 *found = NULL;
michael@0 235 return (idn_success);
michael@0 236 }
michael@0 237
michael@0 238 idn_result_t
michael@0 239 idn_nameprep_isvalidbidi(idn_nameprep_t handle, const uint32_t *str,
michael@0 240 const uint32_t **found) {
michael@0 241 uint32_t v;
michael@0 242 idn_biditype_t first_char;
michael@0 243 idn_biditype_t last_char;
michael@0 244 int found_r_al;
michael@0 245
michael@0 246 assert(handle != NULL && str != NULL && found != NULL);
michael@0 247
michael@0 248 TRACE(("idn_nameprep_isvalidbidi(ctx=%s, str=\"%s\")\n",
michael@0 249 handle->version, idn__debug_ucs4xstring(str, 50)));
michael@0 250
michael@0 251 if (*str == '\0') {
michael@0 252 *found = NULL;
michael@0 253 return (idn_success);
michael@0 254 }
michael@0 255
michael@0 256 /*
michael@0 257 * check first character's type and initialize variables.
michael@0 258 */
michael@0 259 found_r_al = 0;
michael@0 260 if (*str > UCS_MAX) {
michael@0 261 /* This cannot happen, but just in case.. */
michael@0 262 return (idn_invalid_codepoint);
michael@0 263 } else if (*str > UNICODE_MAX) {
michael@0 264 /* It is invalid.. */
michael@0 265 *found = str;
michael@0 266 return (idn_success);
michael@0 267 }
michael@0 268 first_char = last_char = (*(handle->biditype_proc))(*str);
michael@0 269 if (first_char == idn_biditype_r_al) {
michael@0 270 found_r_al = 1;
michael@0 271 }
michael@0 272 str++;
michael@0 273
michael@0 274 /*
michael@0 275 * see whether string is valid or not.
michael@0 276 */
michael@0 277 while (*str != '\0') {
michael@0 278 v = *str;
michael@0 279
michael@0 280 if (v > UCS_MAX) {
michael@0 281 /* This cannot happen, but just in case.. */
michael@0 282 return (idn_invalid_codepoint);
michael@0 283 } else if (v > UNICODE_MAX) {
michael@0 284 /* It is invalid.. */
michael@0 285 *found = str;
michael@0 286 return (idn_success);
michael@0 287 } else {
michael@0 288 last_char = (*(handle->biditype_proc))(v);
michael@0 289 if (found_r_al && last_char == idn_biditype_l) {
michael@0 290 *found = str;
michael@0 291 return (idn_success);
michael@0 292 }
michael@0 293 if (first_char != idn_biditype_r_al && last_char == idn_biditype_r_al) {
michael@0 294 *found = str;
michael@0 295 return (idn_success);
michael@0 296 }
michael@0 297 if (last_char == idn_biditype_r_al) {
michael@0 298 found_r_al = 1;
michael@0 299 }
michael@0 300 }
michael@0 301 str++;
michael@0 302 }
michael@0 303
michael@0 304 if (found_r_al) {
michael@0 305 if (last_char != idn_biditype_r_al) {
michael@0 306 *found = str - 1;
michael@0 307 return (idn_success);
michael@0 308 }
michael@0 309 }
michael@0 310
michael@0 311 *found = NULL;
michael@0 312 return (idn_success);
michael@0 313 }
michael@0 314
michael@0 315 idn_result_t
michael@0 316 idn_nameprep_createproc(const char *parameter, void **handlep) {
michael@0 317 return idn_nameprep_create(parameter, (idn_nameprep_t *)handlep);
michael@0 318 }
michael@0 319
michael@0 320 void
michael@0 321 idn_nameprep_destroyproc(void *handle) {
michael@0 322 idn_nameprep_destroy((idn_nameprep_t)handle);
michael@0 323 }
michael@0 324
michael@0 325 idn_result_t
michael@0 326 idn_nameprep_mapproc(void *handle, const uint32_t *from,
michael@0 327 uint32_t *to, size_t tolen) {
michael@0 328 return idn_nameprep_map((idn_nameprep_t)handle, from, to, tolen);
michael@0 329 }
michael@0 330
michael@0 331 idn_result_t
michael@0 332 idn_nameprep_prohibitproc(void *handle, const uint32_t *str,
michael@0 333 const uint32_t **found) {
michael@0 334 return idn_nameprep_isprohibited((idn_nameprep_t)handle, str, found);
michael@0 335 }
michael@0 336
michael@0 337 idn_result_t
michael@0 338 idn_nameprep_unassignedproc(void *handle, const uint32_t *str,
michael@0 339 const uint32_t **found) {
michael@0 340 return idn_nameprep_isunassigned((idn_nameprep_t)handle, str, found);
michael@0 341 }
michael@0 342
michael@0 343 idn_result_t
michael@0 344 idn_nameprep_bidiproc(void *handle, const uint32_t *str,
michael@0 345 const uint32_t **found) {
michael@0 346 return idn_nameprep_isvalidbidi((idn_nameprep_t)handle, str, found);
michael@0 347 }

mercurial