1 /*
2  *                           TERMS AND CONDITIONS
3  *                                   FOR
4  *                         OPEN SOURCE CODE LICENSE
5  *                               Version 1.1
6  *
7  * Japan Registry Services Co., Ltd. ("JPRS"), a Japanese corporation
8  * having its head office at Chiyoda First Bldg. East 13F 3-8-1 Nishi-Kanda,
9  * Chiyoda-ku, Tokyo 101-0065, Japan, grants you the license for open source
10  * code specified in EXHIBIT A the "Code" subject to the following Terms and
11  * Conditions ("OSCL").
12  *
13  * 1. License Grant.
14  *   JPRS hereby grants you a worldwide, royalty-free, non-exclusive
15  *   license, subject to third party intellectual property claims:
16  *   (a) under intellectual property rights (other than patent or
17  *       trademark) licensable by JPRS to use, reproduce, modify, display,
18  *       perform, sublicense and distribute the Code (or portions thereof)
19  *       with or without modifications, and/or as part of a derivative work;
20  *       or
21  *   (b) under claims of the infringement through the making, using,
22  *       offering to sell and/or otherwise disposing the JPRS Revised Code
23  *       (or portions thereof);
24  *   (c) the licenses granted in this Section 1(a) and (b) are effective on
25  *       the date JPRS first distributes the Code to you under the terms of
26  *       this OSCL;
27  *   (d) Notwithstanding the above stated terms, no patent license is
28  *       granted:
29  *       1)  for a code that you delete from the Code;
30  *       2)  separate from the Code; or
31  *       3)  for infringements caused by:
32  *            i) modification of the Code; or
33  *           ii) combination of the Code with other software or devices.
34  *
35  * 2. Consents.
36  *   You agree that:
37  *   (a) you must include a copy of this OSCL and the notice set forth in
38  *       EXHIBIT A with every copy of the Code you distribute;
39  *   (b) you must include a copy of this OSCL and the notice set forth in
40  *       EXHIBIT A with every copy of binary form of the Code in the
41  *       documentation and/or other materials provided with the distribution;
42  *   (c) you may not offer or impose any terms on any source code version
43  *       that alters or restricts the applicable version of this OSCL or
44  *       the recipients' rights hereunder.
45  *   (d) If the terms and conditions are set forth in EXHIBIT A, you must
46  *       comply with those terms and conditions.
47  *
48  * 3. Proprietary Information.
49  *   All trademarks, service marks, patents, copyrights, trade secrets, and
50  *   other proprietary rights in or related to the Code are and will remain
51  *   the exclusive property of JPRS or its licensors, whether or not
52  *   specifically recognized or perfected under local law except specified
53  *   in this OSCL; provided however you agree and understand that the JPRS
54  *   name may not be used to endorse or promote this Code without prior
55  *   written approval of JPRS.
56  *
57  * 4. WARRANTY DISCLAIMER.
58  *   JPRS MAKES NO REPRESENTATIONS AND WARRANTIES REGARDING THE USE OF THE
59  *   CODE, NOR DOES JPRS MAKE ANY REPRESENTATIONS THAT THE CODE WILL BECOME
60  *   COMMERCIALLY AVAILABLE. JPRS, ITS AFFILIATES, AND ITS SUPPLIERS DO NOT
61  *   WARRANT OR REPRESENT THAT THE CODE IS FREE OF ERRORS OR THAT THE CODE
62  *   IS SUITABLE FOR TRANSLATION AND/OR LOCALIZATION. THE CODE IS PROVIDED
63  *   ON AN "AS IS" BASIS AND JPRS AND ITS SUPPLIERS HAVE NO OBLIGATION TO
64  *   CORRECT ERRORS OR TO SUPPORT THE CODE UNDER THIS OSCL FOR ANY REASON.
65  *   TO THE FULL EXTENT PERMITTED BY LAW, ALL OBLIGATIONS ARE HEREBY
66  *   EXCLUDED WHETHER EXPRESS, STATUTORY OR IMPLIED UNDER LAW, COURSE OF
67  *   DEALING, CUSTOM, TRADE USAGE, ORAL OR WRITTEN STATEMENT OR OTHERWISE,
68  *   INCLUDING BUT NOT LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY
69  *   OR FITNESS FOR A PARTICULAR PURPOSE CONCERNING THE CODE.
70  *
71  * 5. NO LIABILITY.
72  *   UNDER NO CIRCUMSTANCES SHALL JPRS AND/OR ITS AFFILIATES, LICENSORS, OR
73  *   REPRESENTATIVES BE LIABLE FOR ANY DAMAGES INCLUDING BUT NOT LIMITED TO
74  *   CONSEQUENTIAL, INDIRECT, SPECIAL, PUNITIVE OR INCIDENTAL DAMAGES,
75  *   WHETHER FORESEEABLE OR UNFORESEEABLE, BASED ON YOUR CLAIMS, INCLUDING,
76  *   BUT NOT LIMITED TO, CLAIMS FOR LOSS OF DATA, GOODWILL, PROFITS, USE OF
77  *   MONEY, INTERRUPTION IN USE OR AVAILABILITY OF DATA, STOPPAGE, IMPLIED
78  *   WARRANTY, BREACH OF CONTRACT, MISREPRESENTATION, NEGLIGENCE, STRICT
79  *   LIABILITY IN TORT, OR OTHERWISE.
80  *
81  * 6. Indemnification.
82  *   You hereby agree to indemnify, defend, and hold harmless JPRS for any
83  *   liability incurred by JRPS due to your terms of warranty, support,
84  *   indemnity, or liability offered by you to any third party.
85  *
86  * 7. Termination.
87  * 7.1 This OSCL shall be automatically terminated in the events that:
88  *   (a) You fail to comply with the terms herein and fail to cure such
89  *       breach within 30 days of becoming aware of the breach;
90  *   (b) You initiate patent or copyright infringement litigation against
91  *       any party (including a cross-claim or counterclaim in a lawsuit)
92  *       alleging that the Code constitutes a direct or indirect patent or
93  *       copyright infringement, in such case, this OSCL to you shall
94  *       terminate as of the date such litigation is filed;
95  * 7.2 In the event of termination under Sections 7.1(a) or 7.1(b) above,
96  *     all end user license agreements (excluding distributors and
97  *     resellers) which have been validly granted by You or any distributor
98  *     hereunder prior to termination shall survive termination.
99  *
100  *
101  * 8. General.
102  *   This OSCL shall be governed by, and construed and enforced in
103  *   accordance with, the laws of Japan. Any litigation or arbitration
104  *   between the parties shall be conducted exclusively in Tokyo, Japan
105  *   except written consent of JPRS provides other venue.
106  *
107  *
108  *                                EXHIBIT A
109  *
110  * The original open source code of idnkit-2 is idnkit-1.0 developed and
111  * conceived by Japan Network Information Center ("JPNIC"), a Japanese
112  * association, Kokusai-Kougyou-Kanda Bldg 6F, 2-3-4 Uchi-Kanda,
113  * Chiyoda-ku, Tokyo 101-0047, Japan, and JPRS modifies above original code
114  * under following Terms and Conditions set forth by JPNIC.
115  *
116  *                                  JPNIC
117  *
118  * Copyright (c) 2000-2002 Japan Network Information Center.  All rights reserved.
119  *
120  * By using this file, you agree to the terms and conditions set forth bellow.
121  *
122  *                       LICENSE TERMS AND CONDITIONS
123  *
124  * The following License Terms and Conditions apply, unless a different
125  * license is obtained from Japan Network Information Center ("JPNIC"),
126  * a Japanese association, Kokusai-Kougyou-Kanda Bldg 6F, 2-3-4 Uchi-Kanda,
127  * Chiyoda-ku, Tokyo 101-0047, Japan.
128  *
129  * 1. Use, Modification and Redistribution (including distribution of any
130  *    modified or derived work) in source and/or binary forms is permitted
131  *    under this License Terms and Conditions.
132  *
133  * 2. Redistribution of source code must retain the copyright notices as they
134  *    appear in each source code file, this License Terms and Conditions.
135  *
136  * 3. Redistribution in binary form must reproduce the Copyright Notice,
137  *    this License Terms and Conditions, in the documentation and/or other
138  *    materials provided with the distribution. For the purposes of binary
139  *    distribution the "Copyright Notice" refers to the following language:
140  *    "Copyright (c) 2000-2002 Japan Network Information Center.  All rights reserved."
141  *
142  * 4. The name of JPNIC may not be used to endorse or promote products
143  *    derived from this Software without specific prior written approval of
144  *    JPNIC.
145  *
146  * 5. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY JPNIC
147  *    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
148  *    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
149  *    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JPNIC BE LIABLE
150  *    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
151  *    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
152  *    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
153  *    BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
154  *    WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
155  *    OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
156  *    ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
157  *
158  *
159  *                        JPRS Public License Notice
160  *                                   For
161  *                                idnkit-2.
162  *
163  * The contents of this file are subject to the Terms and Conditions for
164  * the Open Source Code License (the "OSCL"). You may not use this file
165  * except in compliance with above terms and conditions. A copy of the OSCL
166  * is available at <http://jprs.co.jp/idn/>.
167  * The JPRS Revised Code is idnkit-2.
168  * The Initial Developer of the JPRS Revised Code is Japan Network
169  * Information Center ("JPNIC"), a Japanese association,
170  * Kokusai-Kougyou-Kanda Bldg 6F, 2-3-4 Uchi-Kanda, Chiyoda-ku, Tokyo
171  * 101-0047, Japan.
172  * "Copyright (c) 2000-2002 Japan Network Information Center.  All rights reserved."
173  * "Copyright (c) 2010-2012 Japan Registry Services Co., Ltd.  All rights reserved."
174  * Contributor(s): ______________________________________.
175  *
176  * If you wish to allow use of your version of this file only under the
177  * above License(s) and not to allow others to use your version of this
178  * file, please indicate your decision by deleting the relevant provisions
179  * above and replacing them with the notice and other provisions required
180  * by the above License(s). If you do not delete the relevant provisions,
181  * a recipient may use your version of this file under either the above
182  * License(s).
183  */
184 
185 #include <config.h>
186 
187 #include <stddef.h>
188 #include <stdlib.h>
189 #include <string.h>
190 
191 #include <idn/assert.h>
192 #include <idn/debug.h>
193 #include <idn/logmacro.h>
194 #include <idn/result.h>
195 #include <idn/res.h>
196 #include <idn/res_internal.h>
197 #include <idn/labellist.h>
198 #include <idn/punycode.h>
199 #include <idn/utf32.h>
200 #include <idn/utf8.h>
201 #include <idn/util.h>
202 
203 #define ENCODE_MASK \
204 	(IDN_UNICODECONV | IDN_MAP | IDN_ASCLOWER | IDN_RTCONV | \
205 	IDN_PROHCHECK | IDN_UNASCHECK | IDN_NFCCHECK | IDN_PREFCHECK | \
206 	IDN_HYPHCHECK | IDN_COMBCHECK | IDN_CTXJCHECK | IDN_CTXOCHECK | \
207 	IDN_CTXOLITECHECK | IDN_BIDICHECK | IDN_LOCALCHECK | IDN_IDNCONV | \
208 	IDN_LENCHECK | IDN_RTCHECK | IDN_LOCALCONV | IDN_LITEFORCEUTF8 | \
209 	IDN_UNDOIFERR)
210 
211 #define DECODE_MASK \
212 	(IDN_UNICODECONV | IDN_MAP | IDN_ASCLOWER | IDN_IDNCONV | \
213 	IDN_PROHCHECK | IDN_UNASCHECK | IDN_NFCCHECK | IDN_PREFCHECK | \
214 	IDN_HYPHCHECK | IDN_COMBCHECK | IDN_CTXJCHECK | IDN_CTXOCHECK | \
215 	IDN_CTXOLITECHECK | IDN_BIDICHECK | IDN_LOCALCHECK | IDN_RTCHECK | \
216 	IDN_LOCALCONV |	IDN_LITEFORCEUTF8 | IDN_UNDOIFERR)
217 
218 static int		have_rtl_label(idn_resconf_t ctx,
219 				       idn__labellist_t labellist);
220 static int		is_ldh_label(idn__labellist_t label);
221 
222 #ifdef LIBIDNKITLITE
223 static const int is_idnkitlite = 1;
224 #else
225 static const int is_idnkitlite = 0;
226 #endif
227 
228 /*
229  * Encode a domain name.
230  */
231 idn_result_t
idn_res_encodename(idn_resconf_t ctx,idn_action_t actions,const char * from,char * to,size_t tolen)232 idn_res_encodename(idn_resconf_t ctx, idn_action_t actions, const char *from,
233 		   char *to, size_t tolen) {
234 	idn_result_t r = idn_success;
235 	char actions_string[ACTION_STRING_BUFSIE];
236 	char *utf8_from = NULL;
237 	unsigned long *utf32_from = NULL;
238 	unsigned long *utf32_to = NULL;
239 	char *utf8_to = NULL;
240 	idn__labellist_t labels = NULL, l;
241 	int have_rtl;
242 
243 	assert(ctx != NULL && from != NULL && to != NULL);
244 
245 	idn__res_actionstostring(actions, actions_string);
246 	TRACE(("idn_res_encodename(actions=%s, from=\"%s\", tolen=%d)\n",
247 		actions_string, idn__debug_xstring(from), (int)tolen));
248 
249 	if (actions & ~ENCODE_MASK) {
250 		WARNING(("idn_res_encodename: invalid actions 0x%x\n",
251 			 actions));
252 		r = idn_invalid_action;
253 		goto ret;
254 	}
255 
256 	if (is_idnkitlite && actions & IDN_LITEFORCEUTF8)
257 		actions &= ~(IDN_LOCALCONV | IDN_UNICODECONV);
258 
259 	/*
260 	 * Convert `from' to UTF-32.
261 	 */
262 	if (actions & IDN_UNICODECONV)
263 		r = idn__res_unicodeconv(ctx, from, &utf8_from);
264 	else {
265 		utf8_from = idn__util_strdup(from);
266 		r = (utf8_from != NULL) ? idn_success : idn_nomemory;
267 	}
268 	if (r != idn_success)
269 		goto ret;
270 
271 	r = idn__res_utf8toutf32(ctx, utf8_from, &utf32_from);
272 	if (r != idn_success)
273 		goto ret;
274 
275 	/*
276 	 * Map.
277 	 */
278 	if (actions & IDN_MAP) {
279 		unsigned long *tmp_from;
280 
281 		r = idn__res_map(ctx, utf32_from, &tmp_from);
282 		if (r != idn_success)
283 			goto ret;
284 		free(utf32_from);
285 		utf32_from = tmp_from;
286 	}
287 
288 	/*
289 	 * Split the name into a list of labels.
290 	 */
291 	if ((utf32_from[0] == '\0') ||
292 	    (utf32_from[0] == '.' && utf32_from[1] == '\0')) {
293 		utf32_to = idn__utf32_strdup(utf32_from);
294 		if (utf32_to == NULL)
295 			r = idn_nomemory;
296 	} else {
297 		r = idn__labellist_create(utf32_from, &labels);
298 	}
299 	if (r != idn_success)
300 		goto ret;
301 
302 	/*
303 	 * Perform conversions and tests.
304 	 */
305 	for (l = labels; l != NULL; l = idn__labellist_next(l)) {
306 		do {
307 			int is_xn;
308 			int is_ldh;
309 
310 			if (actions & IDN_ASCLOWER) {
311 				r = idn__res_asclower(ctx, l);
312 				if (r != idn_success)
313 					break;
314 			}
315 
316 			is_xn = idn__punycode_isacelabel(idn__labellist_getname(l));
317 			r = idn__labellist_setundoname(l);
318 			if (r != idn_success)
319 				break;
320 
321 			if ((actions & IDN_RTCONV) && is_xn) {
322 				r = idn__labellist_setroundtripname(l);
323 				if (r != idn_success)
324 					break;
325 				r = idn__res_idnconv_decode(ctx, l);
326 				if (r != idn_success)
327 					break;
328 			}
329 
330 			is_ldh = is_ldh_label(l);
331 
332 			if ((actions & IDN_PROHCHECK) && !is_ldh) {
333 				r = idn__res_prohcheck(ctx, l);
334 				if (r != idn_success)
335 					break;
336 			}
337 			if ((actions & IDN_UNASCHECK) && !is_ldh) {
338 				r = idn__res_unascheck(ctx, l);
339 				if (r != idn_success)
340 					break;
341 			}
342 			if ((actions & IDN_NFCCHECK) && !is_ldh) {
343 				r = idn__res_nfccheck(ctx, l);
344 				if (r != idn_success)
345 					break;
346 			}
347 			if ((actions & IDN_PREFCHECK) && !is_ldh) {
348 				r = idn__res_prefcheck(ctx, l);
349 				if (r != idn_success)
350 					break;
351 			}
352 			if (actions & IDN_HYPHCHECK) {
353 				r = idn__res_hyphcheck(ctx, l);
354 				if (r != idn_success)
355 					break;
356 			}
357 			if ((actions & IDN_COMBCHECK) && !is_ldh) {
358 				r = idn__res_combcheck(ctx, l);
359 				if (r != idn_success)
360 					break;
361 			}
362 			if ((actions & IDN_CTXJCHECK) && !is_ldh) {
363 				r = idn__res_ctxjcheck(ctx, l);
364 				if (r != idn_success)
365 					break;
366 			}
367 			if ((actions & IDN_CTXOCHECK) && !is_ldh) {
368 				r = idn__res_ctxocheck(ctx, l);
369 				if (r != idn_success)
370 					break;
371 			}
372 			if ((actions & IDN_CTXOLITECHECK) && !is_ldh) {
373 				r = idn__res_ctxolitecheck(ctx, l);
374 				if (r != idn_success)
375 					break;
376 			}
377 		} while (0);
378 
379 		if (r != idn_success && r != idn_nomemory &&
380 		    actions & IDN_UNDOIFERR) {
381 			r = idn__labellist_undo(l);
382 			if (r != idn_success)
383 				goto ret;
384 			TRACE(("idn_res_encodename(): undo (label=\"%s\")\n",
385 			       idn__debug_utf32xstring(idn__labellist_getname(l))));
386 			continue;
387 		}
388 		if (r != idn_success)
389 			goto ret;
390 	}
391 
392 	have_rtl = have_rtl_label(ctx, labels);
393 	for (l = labels; l != NULL; l = idn__labellist_next(l)) {
394 		int is_xn = idn__punycode_isacelabel(idn__labellist_getroundtripname(l));
395 		int is_ldh = is_ldh_label(l);
396 
397 		if (idn__labellist_getundocount(l) > 0)
398 			continue;
399 
400 		do {
401 			if ((actions & IDN_BIDICHECK) && have_rtl) {
402 				r = idn__res_bidicheck(ctx, l);
403 				if (r != idn_success)
404 					break;
405 			}
406 			if (actions & IDN_LOCALCHECK) {
407 				r = idn__res_localcheck(ctx, l);
408 				if (r != idn_success)
409 					break;
410 			}
411 			if (actions & IDN_IDNCONV && !is_ldh) {
412 				r = idn__res_idnconv_encode(ctx, l);
413 				if (r != idn_success)
414 					break;
415 			}
416 			if (actions & IDN_LENCHECK) {
417 				r = idn__res_lencheck(ctx, l);
418 				if (r != idn_success)
419 					break;
420 			}
421 			if ((actions & IDN_RTCHECK) && is_xn) {
422 				r = idn__res_rtcheck_encode(ctx, l);
423 				if (r != idn_success)
424 					break;
425 			}
426 		} while (0);
427 
428 		if (r != idn_success && r != idn_nomemory &&
429 		    actions & IDN_UNDOIFERR) {
430 			r = idn__labellist_undo(l);
431 			if (r != idn_success)
432 				goto ret;
433 			TRACE(("idn_res_encodename(): undo (label=\"%s\")\n",
434 			       idn__debug_utf32xstring(idn__labellist_getname(l))));
435 			continue;
436 		}
437 		if (r != idn_success)
438 			goto ret;
439 	}
440 
441 	/*
442 	 * Join labels.
443 	 */
444 	if (labels != NULL) {
445 		r = idn__res_joinlabels(ctx, labels, &utf32_to);
446 		if (r != idn_success)
447 			goto ret;
448 	}
449 
450 	r = idn__res_utf32toutf8(ctx, utf32_to, &utf8_to);
451 	if (r != idn_success)
452 		goto ret;
453 
454 	/*
455 	 * Perform IDN_LOCALCONV.
456 	 */
457 	if (actions & IDN_LOCALCONV)
458 		r = idn__res_localconv(ctx, utf8_to, to, tolen);
459 	else
460 		r = idn__util_strcpy(to, tolen, utf8_to);
461 
462 ret:
463 	if (r == idn_success) {
464 		TRACE(("idn_res_encodename(): success (to=\"%s\")\n",
465 		       idn__debug_xstring(to)));
466 	} else {
467 		TRACE(("idn_res_encodename(): %s\n", idn_result_tostring(r)));
468 	}
469 	free(utf8_to);
470 	free(utf32_to);
471 	free(utf32_from);
472 	free(utf8_from);
473 	if (labels != NULL)
474 		idn__labellist_destroy(labels);
475 	return (r);
476 }
477 
478 /*
479  * Decode a domain name.
480  */
481 idn_result_t
idn_res_decodename(idn_resconf_t ctx,idn_action_t actions,const char * from,char * to,size_t tolen)482 idn_res_decodename(idn_resconf_t ctx, idn_action_t actions, const char *from,
483 		    char *to, size_t tolen) {
484 	idn_result_t r = idn_success;
485 	char actions_string[ACTION_STRING_BUFSIE];
486 	char *utf8_from = NULL;
487 	unsigned long *utf32_from = NULL;
488 	unsigned long *utf32_to = NULL;
489 	char *utf8_to = NULL;
490 	idn__labellist_t labels = NULL, l;
491 	int have_rtl;
492 
493 	assert(ctx != NULL && from != NULL && to != NULL);
494 
495 	idn__res_actionstostring(actions, actions_string);
496 	TRACE(("idn_res_decodename(actions=%s, from=\"%s\", tolen=%d)\n",
497 		actions_string, idn__debug_xstring(from), (int)tolen));
498 
499 	if (actions & ~DECODE_MASK) {
500 		WARNING(("idn_res_decodename: invalid actions 0x%x\n",
501 			 actions));
502 		r = idn_invalid_action;
503 		goto ret;
504 	}
505 
506 	if (is_idnkitlite && actions & IDN_LITEFORCEUTF8)
507 		actions &= ~(IDN_LOCALCONV | IDN_UNICODECONV);
508 
509 	/*
510 	 * Convert `from' to UTF-32.
511 	 */
512 	if (actions & IDN_UNICODECONV)
513 		r = idn__res_unicodeconv(ctx, from, &utf8_from);
514 	else {
515 		utf8_from = idn__util_strdup(from);
516 		r = (utf8_from != NULL) ? idn_success : idn_nomemory;
517 	}
518 	if (r != idn_success)
519 		goto ret;
520 
521 	r = idn__res_utf8toutf32(ctx, utf8_from, &utf32_from);
522 	if (r != idn_success)
523 		goto ret;
524 
525 	/*
526 	 * Map.
527 	 */
528 	if (actions & IDN_MAP) {
529 		unsigned long *tmp_from;
530 
531 		r = idn__res_map(ctx, utf32_from, &tmp_from);
532 		if (r != idn_success)
533 			goto ret;
534 		free(utf32_from);
535 		utf32_from = tmp_from;
536 	}
537 
538 	/*
539 	 * Split the name into a list of labels.
540 	 */
541 	if ((utf32_from[0] == '\0') ||
542 	    (utf32_from[0] == '.' && utf32_from[1] == '\0')) {
543 		utf32_to = idn__utf32_strdup(utf32_from);
544 		if (utf32_to == NULL)
545 			r = idn_nomemory;
546 	} else {
547 		r = idn__labellist_create(utf32_from, &labels);
548 	}
549 	if (r != idn_success)
550 		goto ret;
551 
552 	/*
553 	 * Perform conversions and tests.
554 	 */
555 	for (l = labels; l != NULL; l = idn__labellist_next(l)) {
556 		do {
557 			int is_xn;
558 			int is_ldh;
559 
560 			if (actions & IDN_ASCLOWER) {
561 				r = idn__res_asclower(ctx, l);
562 				if (r != idn_success)
563 					break;
564 			}
565 
566 			is_xn  = idn__punycode_isacelabel(idn__labellist_getname(l));
567 			r = idn__labellist_setundoname(l);
568 			if (r != idn_success)
569 				break;
570 
571 			if ((actions & IDN_IDNCONV) && is_xn) {
572 				r = idn__labellist_setroundtripname(l);
573 				if (r != idn_success)
574 					break;
575 				r = idn__res_idnconv_decode(ctx, l);
576 				if (r != idn_success)
577 					break;
578 			}
579 
580 			is_ldh = is_ldh_label(l);
581 
582 			if ((actions & IDN_PROHCHECK) && !is_ldh) {
583 				r = idn__res_prohcheck(ctx, l);
584 				if (r != idn_success)
585 					break;
586 			}
587 			if ((actions & IDN_UNASCHECK) && !is_ldh) {
588 				r = idn__res_unascheck(ctx, l);
589 				if (r != idn_success)
590 					break;
591 			}
592 			if ((actions & IDN_NFCCHECK) && !is_ldh) {
593 				r = idn__res_nfccheck(ctx, l);
594 				if (r != idn_success)
595 					break;
596 			}
597 			if ((actions & IDN_PREFCHECK) && !is_ldh) {
598 				r = idn__res_prefcheck(ctx, l);
599 				if (r != idn_success)
600 					break;
601 			}
602 			if (actions & IDN_HYPHCHECK) {
603 				r = idn__res_hyphcheck(ctx, l);
604 				if (r != idn_success)
605 					break;
606 			}
607 			if ((actions & IDN_COMBCHECK) && !is_ldh) {
608 				r = idn__res_combcheck(ctx, l);
609 				if (r != idn_success)
610 					break;
611 			}
612 			if ((actions & IDN_CTXJCHECK) && !is_ldh) {
613 				r = idn__res_ctxjcheck(ctx, l);
614 				if (r != idn_success)
615 					break;
616 			}
617 			if ((actions & IDN_CTXOCHECK) && !is_ldh) {
618 				r = idn__res_ctxocheck(ctx, l);
619 				if (r != idn_success)
620 					break;
621 			}
622 			if ((actions & IDN_CTXOLITECHECK) && !is_ldh) {
623 				r = idn__res_ctxolitecheck(ctx, l);
624 				if (r != idn_success)
625 					break;
626 			}
627 		} while (0);
628 
629 		if (r != idn_success && r != idn_nomemory &&
630 		    actions & IDN_UNDOIFERR) {
631 			r = idn__labellist_undo(l);
632 			if (r != idn_success)
633 				goto ret;
634 			TRACE(("idn_res_decodename(): undo (label=\"%s\")\n",
635 			       idn__debug_utf32xstring(idn__labellist_getname(l))));
636 			continue;
637 		}
638 		if (r != idn_success)
639 			goto ret;
640 	}
641 
642 	have_rtl = have_rtl_label(ctx, labels);
643 	for (l = labels; l != NULL; l = idn__labellist_next(l)) {
644 		int is_xn = idn__punycode_isacelabel(idn__labellist_getroundtripname(l));
645 
646 		do {
647 			if ((actions & IDN_BIDICHECK) && have_rtl) {
648 				r = idn__res_bidicheck(ctx, l);
649 				if (r != idn_success)
650 					break;
651 			}
652 			if (actions & IDN_LOCALCHECK) {
653 				r = idn__res_localcheck(ctx, l);
654 				if (r != idn_success)
655 					break;
656 			}
657 			if ((actions & IDN_RTCHECK) && is_xn) {
658 				r = idn__res_rtcheck_decode(ctx, l);
659 				if (r != idn_success)
660 					break;
661 			}
662 		} while (0);
663 
664 		if (r != idn_success && r != idn_nomemory &&
665 		    actions & IDN_UNDOIFERR) {
666 			r = idn__labellist_undo(l);
667 			if (r != idn_success)
668 				goto ret;
669 			TRACE(("idn_res_decodename(): undo (label=\"%s\")\n",
670 			       idn__debug_utf32xstring(idn__labellist_getname(l))));
671 			continue;
672 		}
673 		if (r != idn_success)
674 			goto ret;
675 	}
676 
677 	/*
678 	 * Join labels.
679 	 */
680 	if (labels != NULL) {
681 		r = idn__res_joinlabels(ctx, labels, &utf32_to);
682 		if (r != idn_success)
683 			goto ret;
684 	}
685 
686 	r = idn__res_utf32toutf8(ctx, utf32_to, &utf8_to);
687 	if (r != idn_success)
688 		goto ret;
689 
690 	/*
691 	 * Perform IDN_LOCALCONV.
692 	 */
693 	if (actions & IDN_LOCALCONV)
694 		r = idn__res_localconv(ctx, utf8_to, to, tolen);
695 	else
696 		r = idn__util_strcpy(to, tolen, utf8_to);
697 
698 ret:
699 	if (r == idn_success) {
700 		TRACE(("idn_res_decodename(): success (to=\"%s\")\n",
701 		       idn__debug_xstring(to)));
702 	} else {
703 		TRACE(("idn_res_decodename(): %s\n", idn_result_tostring(r)));
704 	}
705 	free(utf8_to);
706 	free(utf32_to);
707 	free(utf32_from);
708 	free(utf8_from);
709 	if (labels != NULL)
710 		idn__labellist_destroy(labels);
711 	return (r);
712 }
713 
714 /*
715  * Decode a domain name auxiliary encoding support.
716  */
717 idn_result_t
idn_res_decodename2(idn_resconf_t ctx,idn_action_t actions,const char * from,char * to,size_t tolen,const char * auxencoding)718 idn_res_decodename2(idn_resconf_t ctx, idn_action_t actions, const char *from,
719 		    char *to, size_t tolen, const char *auxencoding) {
720 	idn_result_t r = idn_success;
721 	char actions_string[ACTION_STRING_BUFSIE];
722 	idn_resconf_t auxctx = NULL;
723 	char *utf8_from = NULL;
724 
725 	assert(ctx != NULL && from != NULL && to != NULL);
726 
727 	idn__res_actionstostring(actions, actions_string);
728 	TRACE(("idn_res_decodename2(actions=%s, from=\"%s\", tolen=%d, "
729 		"auxencoding=\"%s\")\n",
730 		actions_string, idn__debug_xstring(from), (int)tolen,
731 		idn__debug_xstring(auxencoding)));
732 
733 	if (auxencoding == NULL)
734 		auxencoding = IDN__UTF8_ENCODINGNAME;
735 
736 	/*
737 	 * Convert `from' to UTF-8.
738 	 */
739 	r = idn_resconf_create(&auxctx);
740 	if (r != idn_success)
741 		goto ret;
742 	r = idn_resconf_setlocalencoding(auxctx, auxencoding);
743 	if (r != idn_success)
744 		goto ret;
745 	r = idn__res_unicodeconv(auxctx, from, &utf8_from);
746 	if (r != idn_success)
747 		goto ret;
748 
749 	r = idn_res_decodename(ctx, actions & ~IDN_UNICODECONV, utf8_from,
750 			       to, tolen);
751 
752 ret:
753 	if (r == idn_success) {
754 		TRACE(("idn_res_decodename2(): success (to=\"%s\")\n",
755 		       idn__debug_xstring(to)));
756 	} else {
757 		TRACE(("idn_res_decodename2(): %s\n", idn_result_tostring(r)));
758 	}
759 
760 	free(utf8_from);
761 	if (auxctx != NULL)
762 		idn_resconf_destroy(auxctx);
763 
764 	return (r);
765 }
766 
767 /*
768  * Compare two domain names.
769  */
770 idn_result_t
idn_res_comparenames(idn_resconf_t ctx,idn_action_t actions,const char * name1,const char * name2)771 idn_res_comparenames(idn_resconf_t ctx, idn_action_t actions,
772 		     const char *name1, const char *name2) {
773 	return (idn_res_comparenames2(ctx, actions, name1, actions, name2));
774 }
775 
776 idn_result_t
idn_res_comparenames2(idn_resconf_t ctx,idn_action_t actions1,const char * name1,idn_action_t actions2,const char * name2)777 idn_res_comparenames2(idn_resconf_t ctx,
778 		      idn_action_t actions1, const char *name1,
779 		      idn_action_t actions2, const char *name2) {
780 	idn_result_t r = idn_success;
781 	char actions1_string[ACTION_STRING_BUFSIE];
782 	char actions2_string[ACTION_STRING_BUFSIE];
783 	char *to1 = NULL;
784 	char *to2 = NULL;
785 	size_t tolen1 = 256;  /* may be large enough. */
786 	size_t tolen2 = 256;  /* may be large enough. */
787 
788 	assert(ctx != NULL && name1 != NULL && name2 != NULL);
789 
790 	idn__res_actionstostring(actions1, actions1_string);
791 	idn__res_actionstostring(actions2, actions2_string);
792 	TRACE(("idn_res_comparenames2(actions1=%s, name1=\"%s\", "
793 	       "actions2=%s, name2=\"%s\")\n",
794 		actions1_string, idn__debug_xstring(name1),
795 		actions2_string, idn__debug_xstring(name2)));
796 
797 	for (;;) {
798 		void *new_to1;
799 
800 		new_to1 = realloc(to1, sizeof(*to1) * tolen1);
801 		if (new_to1 == NULL) {
802 			r = idn_nomemory;
803 			goto ret;
804 		}
805 		to1 = (char *)new_to1;
806 		r = idn_res_encodename(ctx, actions1, name1, to1, tolen1);
807 		if (r == idn_success)
808 			break;
809 		else if (r != idn_buffer_overflow)
810 			goto ret;
811 		tolen1 *= 2;
812 	}
813 
814 	for (;;) {
815 		void *new_to2;
816 
817 		new_to2 = realloc(to2, sizeof(*to2) * tolen2);
818 		if (new_to2 == NULL) {
819 			r = idn_nomemory;
820 			goto ret;
821 		}
822 		to2 = (char *)new_to2;
823 		r = idn_res_encodename(ctx, actions2, name2, to2, tolen2);
824 		if (r == idn_success)
825 			break;
826 		else if (r != idn_buffer_overflow)
827 			goto ret;
828 		tolen2 *= 2;
829 	}
830 
831 	r = (idn__util_strcasecmp(to1, to2) == 0) ? idn_success : idn_neq;
832 
833 ret:
834 	if (r == idn_success) {
835 		TRACE(("idn_res_comparenames2(): success "
836 		       "(name1=name2=\"%s\")\n",
837 		       idn__debug_xstring(to1)));
838 	} else if (r == idn_neq) {
839 		TRACE(("idn_res_comparenames2(): neq "
840 		       "(name1=\"%s\" <=> name2=\"%s\")\n",
841 		       idn__debug_xstring(to1),
842 		       idn__debug_xstring(to2)));
843 	} else {
844 		TRACE(("idn_res_comparenames2(): %s\n",
845 		       idn_result_tostring(r)));
846 	}
847 	free(to1);
848 	free(to2);
849 
850 	return (r);
851 }
852 
853 idn_result_t
idn_res_checkname(idn_resconf_t ctx,idn_action_t actions,const char * name)854 idn_res_checkname(idn_resconf_t ctx, idn_action_t actions, const char *name) {
855 	idn_result_t r = idn_success;
856 	char actions_string[ACTION_STRING_BUFSIE];
857 	char *to = NULL;
858 	size_t tolen = 256;  /* may be large enough. */
859 
860 	assert(ctx != NULL && name != NULL);
861 
862 	idn__res_actionstostring(actions, actions_string);
863 	TRACE(("idn_res_checkname(actions=%s, name=\"%s\")\n",
864 		actions_string, idn__debug_xstring(name)));
865 
866 	for (;;) {
867 		void *new_to;
868 
869 		new_to = realloc(to, sizeof(*to) * tolen);
870 		if (new_to == NULL) {
871 			r = idn_nomemory;
872 			goto ret;
873 		}
874 		to = (char *)new_to;
875 		r = idn_res_encodename(ctx, actions, name, to, tolen);
876 		if (r == idn_success)
877 			break;
878 		else if (r != idn_buffer_overflow)
879 			goto ret;
880 		tolen *= 2;
881 	}
882 
883 ret:
884 	if (r == idn_success) {
885 		TRACE(("idn_res_checkname(): success (name=\"%s\")\n",
886 		       idn__debug_xstring(to)));
887 	} else {
888 		TRACE(("idn_res_checkname(): %s\n", idn_result_tostring(r)));
889 	}
890 	free(to);
891 
892 	return (r);
893 }
894 
895 /*
896  * Check if 'labellist' has at least one RTL label.
897  */
898 static int
have_rtl_label(idn_resconf_t ctx,idn__labellist_t labellist)899 have_rtl_label(idn_resconf_t ctx, idn__labellist_t labellist) {
900 	idn__labellist_t l;
901 
902 	for (l = labellist; l != NULL; l = idn__labellist_next(l)) {
903 		if (idn__res_isrtllabel(ctx, l))
904 			return (1);
905 	}
906 
907 	return (0);
908 }
909 
910 /*
911  * Check if 'label' is an LDH label.
912  */
913 static int
is_ldh_label(idn__labellist_t label)914 is_ldh_label(idn__labellist_t label) {
915 	const unsigned long *l;
916 
917 	l = idn__labellist_getname(label);
918 	if (l == NULL)
919 		return (1);
920 
921 	while (*l != '\0') {
922 		if (!('A' <= *l && *l <= 'Z') &&
923 		    !('a' <= *l && *l <= 'z') &&
924 		    !('0' <= *l && *l <= '9') &&
925 		    *l != '-') {
926 			return (0);
927 		}
928 		l++;
929 	}
930 
931 	return (1);
932 }
933 
934 /*
935  * Convert 'actions' to a string.
936  */
937 struct action_name_table {
938 	idn_action_t action;
939 	char *name;
940 };
941 
942 static const struct action_name_table
943 combined_action_name_table[] = {
944 	{IDN_DECODE_REGIST,	"DECODE_REGIST"},
945 	{IDN_DECODE_LOOKUP,	"DECODE_LOOKUP"},
946 	{IDN_ENCODE_REGIST,	"ENCODE_REGIST"},
947 	{IDN_ENCODE_LOOKUP,	"ENCODE_LOOKUP"},
948 	{IDN_COMPARE_REGIST,	"COMPARE_REGIST"},
949 	{IDN_COMPARE_LOOKUP,	"COMPARE_LOOKUP"},
950 	{IDN_CHECK_REGIST,	"CHECK_REGIST"},
951 	{IDN_CHECK_LOOKUP,	"CHECK_LOOKUP"},
952 	{0,			NULL}
953 };
954 
955 static const struct action_name_table
956 single_action_name_table[] = {
957 	{IDN_UNICODECONV,	"UNICODECONV"},
958 	{IDN_MAP,		"MAP"},
959 	{IDN_ASCLOWER,		"ASCLOWER"},
960 	{IDN_RTCONV,		"RTCONV"},
961 	{IDN_PROHCHECK,		"PROHCHECK"},
962 	{IDN_UNASCHECK,		"UNASCHECK"},
963 	{IDN_NFCCHECK,		"NFCCHECK"},
964 	{IDN_PREFCHECK,		"PREFCHECK"},
965 	{IDN_HYPHCHECK,		"HYPHCHECK"},
966 	{IDN_COMBCHECK,		"COMBCHECK"},
967 	{IDN_CTXJCHECK,		"CTXJCHECK"},
968 	{IDN_CTXOCHECK,		"CTXOCHECK"},
969 	{IDN_CTXOLITECHECK,	"CTXOLITECHECK"},
970 	{IDN_BIDICHECK,		"BIDICHECK"},
971 	{IDN_LOCALCHECK,	"LOCALCHECK"},
972 	{IDN_IDNCONV,		"IDNCONV"},
973 	{IDN_LENCHECK,		"LENCHECK"},
974 	{IDN_RTCHECK,		"RTCHECK"},
975 	{IDN_LOCALCONV,		"LOCALCONV"},
976 	{IDN_UNDOIFERR,		"UNDOIFERR"},
977 	{IDN_LITEFORCEUTF8,	"LITEFORCEUTF8"},
978 	{0,			NULL}
979 };
980 
981 void
idn__res_actionstostring(idn_action_t actions,char * string)982 idn__res_actionstostring(idn_action_t actions, char *string) {
983 	const struct action_name_table *t;
984 	const idn_action_t aux_actions =
985 		IDN_LOCALCONV | IDN_LOCALCHECK | IDN_UNDOIFERR;
986 
987 	*string = '\0';
988 	for (t = combined_action_name_table; t->name != NULL; t++) {
989 		if ((actions | aux_actions) == (t->action | aux_actions)) {
990 			strcpy(string, t->name);
991 			actions &= ~t->action;
992 			break;
993 		}
994 	}
995 
996 	for (t = single_action_name_table; t->name != NULL; t++) {
997 		if (actions & t->action) {
998 			if (*string != '\0')
999 				strcat(string, "|");
1000 			strcat(string, t->name);
1001 		}
1002 	}
1003 }
1004 
1005 /*
1006  * Obsolete functions.
1007  */
1008 void
idn_res_enable(int on_off)1009 idn_res_enable(int on_off) {
1010 	/* no operation. */
1011 }
1012