1 #ifndef lint
2 static char *rcsid = "$Id$";
3 #endif
4 
5 /*
6  * idn module for libwww: see http://dev.w3.org/cvsweb/libwww/modules/idn/
7  *
8  * Changes by Martin Duerst (W3C) are:
9  *   Copyright (C) 2003 World Wide Web Consortium, (Massachusetts
10  *   Institute of Technology, European Research Consortium for Informatics
11  *   and Mathematics, Keio University). All Rights Reserved. This work is
12  *   distributed under the W3C Software License [1] in the hope that
13  *   it will be useful, but WITHOUT ANY WARRANTY; without even the implied
14  *   warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15  *
16  *   [1] http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
17  */
18 
19 /* changes: MJD 2003-03-20: removed call to getregistrystring
20  *          MJD 2003-03-20: removed localencoding.h
21  *          MJD 2003-03-21: set WITHOUT_ICONV
22  */
23 
24 /* Original sources are: */
25 /*
26  * Copyright (c) 2000 Japan Network Information Center.  All rights reserved.
27  *
28  * By using this file, you agree to the terms and conditions set forth bellow.
29  *
30  * 			LICENSE TERMS AND CONDITIONS
31  *
32  * The following License Terms and Conditions apply, unless a different
33  * license is obtained from Japan Network Information Center ("JPNIC"),
34  * a Japanese association, Kokusai-Kougyou-Kanda Bldg 6F, 2-3-4 Uchi-Kanda,
35  * Chiyoda-ku, Tokyo 101-0047, Japan.
36  *
37  * 1. Use, Modification and Redistribution (including distribution of any
38  *    modified or derived work) in source and/or binary forms is permitted
39  *    under this License Terms and Conditions.
40  *
41  * 2. Redistribution of source code must retain the copyright notices as they
42  *    appear in each source code file, this License Terms and Conditions.
43  *
44  * 3. Redistribution in binary form must reproduce the Copyright Notice,
45  *    this License Terms and Conditions, in the documentation and/or other
46  *    materials provided with the distribution.  For the purposes of binary
47  *    distribution the "Copyright Notice" refers to the following language:
48  *    "Copyright (c) 2000-2002 Japan Network Information Center.  All rights reserved."
49  *
50  * 4. The name of JPNIC may not be used to endorse or promote products
51  *    derived from this Software without specific prior written approval of
52  *    JPNIC.
53  *
54  * 5. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY JPNIC
55  *    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
56  *    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
57  *    PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL JPNIC BE LIABLE
58  *    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
59  *    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
60  *    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
61  *    BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
62  *    WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
63  *    OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
64  *    ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
65  */
66 
67 #define WITHOUT_ICONV
68 
69 #include <config.h>
70 
71 #include <stddef.h>
72 #include <stdarg.h>
73 #include <stdlib.h>
74 #include <stdio.h>
75 #include <string.h>
76 #include <ctype.h>
77 #include <errno.h>
78 #ifdef HAVE_UNISTD_H
79 #include <unistd.h>
80 #endif
81 #ifdef HAVE_PWD_H
82 #include <pwd.h>
83 #endif
84 
85 #include <idn/result.h>
86 #include <idn/assert.h>
87 #include <idn/logmacro.h>
88 #include <idn/converter.h>
89 #include <idn/nameprep.h>
90 #include <idn/normalizer.h>
91 #include <idn/checker.h>
92 #include <idn/mapper.h>
93 #include <idn/mapselector.h>
94 #include <idn/delimitermap.h>
95 /*#include <idn/localencoding.h>*/
96 #include <idn/resconf.h>
97 #include <idn/debug.h>
98 #include <idn/util.h>
99 
100 #ifdef WIN32
101 #define MAX_PATH_SIZE		500	/* a good longer than MAX_PATH */
102 #define IDNVAL_CONFFILE		"ConfFile"
103 #else /* WIN32 */
104 
105 #ifndef IDN_RESCONF_DIR
106 #define IDN_RESCONF_DIR		"/etc"
107 #endif
108 #define IDN_RESCONF_FILE	IDN_RESCONF_DIR "/idn.conf"
109 #define IDN_USER_RESCONF_FILE	"/.idnrc"
110 
111 #endif /* WIN32 */
112 
113 #define MAX_CONF_LINE_LENGTH	255
114 #define MAX_CONF_LINE_ARGS	63
115 
116 #define DEFAULT_CONF_NAMEPREP		0x0001
117 #define DEFAULT_CONF_IDN_ENCODING	0x0010
118 #define DEFAULT_CONF_ALL		(DEFAULT_CONF_NAMEPREP | \
119 					DEFAULT_CONF_IDN_ENCODING)
120 
121 #define IDN_ENCODING_CURRENT	"Punycode"
122 
123 #ifdef ENABLE_MDNKIT_COMPAT
124 #define MDN_RESCONF_FILE	IDN_RESCONF_DIR "/mdn.conf"
125 #endif
126 
127 struct idn_resconf {
128 	int local_converter_is_static;
129 	idn_converter_t local_converter;
130 	idn_converter_t idn_converter;
131         idn_converter_t aux_idn_converter;
132 	idn_normalizer_t normalizer;
133 	idn_checker_t prohibit_checker;
134 	idn_checker_t unassigned_checker;
135 	idn_checker_t bidi_checker;
136 	idn_mapper_t mapper;
137 	idn_mapselector_t local_mapper;
138 	idn_delimitermap_t delimiter_mapper;
139 	int reference_count;
140 };
141 
142 static int initialized;
143 
144 #ifndef WIN32
145 static const char *	userhomedir(void);
146 #endif
147 static idn_result_t	open_userdefaultfile(FILE **fpp);
148 static idn_result_t	open_defaultfile(FILE **fpp);
149 static idn_result_t	parse_conf(idn_resconf_t ctx, FILE *fp);
150 static idn_result_t	parse_idn_encoding(idn_resconf_t ctx, char *args,
151 					   int lineno);
152 static idn_result_t	parse_local_map(idn_resconf_t ctx, char *args,
153 					int lineno);
154 static idn_result_t	parse_nameprep(idn_resconf_t ctx, char *args,
155 				       int lineno);
156 static int		split_args(char *s, char **av, int max_ac);
157 static void		resetconf(idn_resconf_t ctx);
158 #ifndef WITHOUT_ICONV
159 static idn_result_t	update_local_converter(idn_resconf_t ctx);
160 #endif
161 static idn_result_t	setdefaults_body(idn_resconf_t ctx, int conf_mask);
162 
163 idn_result_t
idn_resconf_initialize(void)164 idn_resconf_initialize(void) {
165 	idn_result_t r;
166 
167 	TRACE(("idn_resconf_initialize()\n"));
168 
169 	if (initialized) {
170 		r = idn_success;
171 		goto ret;
172 	}
173 
174 	/*
175 	 * Initialize sub modules.
176 	 */
177 	if ((r = idn_converter_initialize()) != idn_success)
178 		goto ret;
179 	if ((r = idn_normalizer_initialize()) != idn_success)
180 		goto ret;
181 	if ((r = idn_checker_initialize()) != idn_success)
182 		goto ret;
183 	if ((r = idn_mapselector_initialize()) != idn_success)
184 		goto ret;
185 	if ((r = idn_mapper_initialize()) != idn_success)
186 		goto ret;
187 
188 	r = idn_success;
189 	initialized = 1;
190 ret:
191 	TRACE(("idn_resconf_initialize(): %s\n", idn_result_tostring(r)));
192 	return (r);
193 }
194 
195 idn_result_t
idn_resconf_create(idn_resconf_t * ctxp)196 idn_resconf_create(idn_resconf_t *ctxp) {
197 	idn_resconf_t ctx = NULL;
198 	idn_result_t r;
199 
200 	assert(ctxp != NULL);
201 
202 	TRACE(("idn_resconf_create()\n"));
203 
204 	if (!initialized) {
205 		r = idn_failure;
206 		goto ret;
207 	}
208 	if ((ctx = malloc(sizeof(*ctx))) == NULL) {
209 		r = idn_nomemory;
210 		goto ret;
211 	}
212 
213 	ctx->local_converter_is_static = 0;
214 	ctx->local_converter = NULL;
215 	ctx->idn_converter = NULL;
216 	ctx->aux_idn_converter = NULL;
217 	ctx->normalizer = NULL;
218 	ctx->prohibit_checker = NULL;
219 	ctx->unassigned_checker = NULL;
220 	ctx->bidi_checker = NULL;
221 	ctx->mapper = NULL;
222 	ctx->local_mapper = NULL;
223 	ctx->reference_count = 1;
224 
225 	r = idn_delimitermap_create(&ctx->delimiter_mapper);
226 	if (r != idn_success)
227 		goto ret;
228 
229 	*ctxp = ctx;
230 	r = idn_success;
231 ret:
232 	TRACE(("idn_resconf_create(): %s\n", idn_result_tostring(r)));
233 	return (r);
234 }
235 
236 char *
idn_resconf_defaultfile()237 idn_resconf_defaultfile() {
238 #ifdef WIN32
239 /*	static char default_path[MAX_PATH_SIZE];
240 
241 	if (idn__util_getregistrystring(idn__util_hkey_localmachine,
242 					IDNVAL_CONFFILE, default_path,
243 					sizeof(default_path))) {
244 		return (default_path);
245 	} else {*/
246 		return (NULL);
247 /*	}*/
248 #else
249 	return (IDN_RESCONF_FILE);
250 #endif
251 }
252 
253 #ifndef WIN32
254 static const char *
userhomedir()255 userhomedir() {
256 	uid_t uid;
257 	struct passwd *pwd;
258 
259 	uid = getuid();
260 	pwd = getpwuid(uid);
261 	if (pwd == NULL) {
262 		return (NULL);
263 	}
264 
265 	return (pwd->pw_dir);
266 }
267 #endif
268 
269 static idn_result_t
open_userdefaultfile(FILE ** fpp)270 open_userdefaultfile(FILE **fpp) {
271 #ifdef WIN32
272 /*	char user_path[MAX_PATH_SIZE];
273 
274 	TRACE(("open_userdefaultfile()\n"));
275 
276 	if (idn__util_getregistrystring(idn__util_hkey_currentuser,
277 					IDNVAL_CONFFILE, user_path,
278 					sizeof(user_path)) == 0) {
279 		return (idn_nofile);
280 	}
281 	*fpp = fopen(user_path, "r");
282 	if (*fpp == NULL) {*/
283 		return (idn_nofile);
284 /*	}*/
285 	return (idn_success);
286 #else /* WIN32 */
287 	const char *homedir;
288 	char *file;
289 	int len;
290 
291 	TRACE(("open_userdefaultfile()\n"));
292 
293 	homedir = userhomedir();
294 	len = strlen(IDN_USER_RESCONF_FILE) + 1;
295 	if (homedir != NULL) {
296 		len += strlen(homedir);
297 	} else {
298 		return (idn_notfound);
299 	}
300 
301 	file = (char *)malloc(sizeof(char) * len);
302 	if (file == NULL) {
303 		WARNING(("open_userdefaultfile(): malloc failed\n"));
304 		return (idn_nomemory);
305 	}
306 
307 	(void)strcpy(file, homedir);
308 	strcat(file, IDN_USER_RESCONF_FILE);
309 
310 	*fpp = fopen(file, "r");
311 	free(file);
312 	if (*fpp == NULL) {
313 		return (idn_nofile);
314 	}
315 
316 	return (idn_success);
317 #endif /* WIN32 */
318 }
319 
320 static idn_result_t
open_defaultfile(FILE ** fpp)321 open_defaultfile(FILE **fpp) {
322 	idn_result_t r;
323 	const char *file;
324 
325 	r = open_userdefaultfile(fpp);
326 	if (r == idn_nofile || r == idn_notfound) {
327 		TRACE(("open_defaultfile: "
328 		       "cannot open user configuration file\n"));
329 		file = idn_resconf_defaultfile();
330 		*fpp = fopen(file, "r");
331 #ifdef ENABLE_MDNKIT_COMPAT
332 		if (*fpp == NULL)
333 			*fpp = fopen(MDN_RESCONF_FILE, "r");
334 #endif
335 		if (*fpp == NULL) {
336 			TRACE(("open_defaultfile: "
337 			       "cannot open system configuration file\n"));
338 			return (idn_nofile);
339 		}
340 	} else if (r != idn_success) {
341 		return (r);
342 	}
343 
344 	return (idn_success);
345 }
346 
347 idn_result_t
idn_resconf_loadfile(idn_resconf_t ctx,const char * file)348 idn_resconf_loadfile(idn_resconf_t ctx, const char *file) {
349 	FILE *fp = NULL;
350 	idn_result_t r;
351 
352 	assert(ctx != NULL);
353 
354 	TRACE(("idn_resconf_loadfile(file=%s)\n",
355 	      file == NULL ? "<null>" : file));
356 
357 	resetconf(ctx);
358 	r = idn_delimitermap_create(&ctx->delimiter_mapper);
359 	if (r != idn_success) {
360 		goto ret;
361 	}
362 
363 	if (file == NULL) {
364 		r = open_defaultfile(&fp);
365 		if (r == idn_nofile || r == idn_notfound) {
366 			r = setdefaults_body(ctx, 0);
367 			goto ret;
368 		} else if (r != idn_success) {
369 			goto ret;
370 		}
371 	} else {
372 		fp = fopen(file, "r");
373 		if (fp == NULL) {
374 			TRACE(("idn_resconf_loadfile: cannot open %-.40s\n",
375 			       file));
376 			r = idn_nofile;
377 			goto ret;
378 		}
379 	}
380 
381 	r = parse_conf(ctx, fp);
382 	fclose(fp);
383 
384 ret:
385 	TRACE(("idn_resconf_loadfile(): %s\n", idn_result_tostring(r)));
386 	return (r);
387 }
388 
389 void
idn_resconf_destroy(idn_resconf_t ctx)390 idn_resconf_destroy(idn_resconf_t ctx) {
391 	assert(ctx != NULL);
392 
393 	TRACE(("idn_resconf_destroy()\n"));
394 
395 	ctx->reference_count--;
396 	if (ctx->reference_count <= 0) {
397 		resetconf(ctx);
398 		free(ctx);
399 		TRACE(("idn_resconf_destroy: the object is destroyed\n"));
400 	} else {
401 		TRACE(("idn_resconf_destroy(): "
402 		       "update reference count (%d->%d)\n",
403 		       ctx->reference_count + 1, ctx->reference_count));
404 	}
405 }
406 
407 void
idn_resconf_incrref(idn_resconf_t ctx)408 idn_resconf_incrref(idn_resconf_t ctx) {
409 	assert(ctx != NULL);
410 
411 	TRACE(("idn_resconf_incrref()\n"));
412 	TRACE(("idn_resconf_incrref: update reference count (%d->%d)\n",
413 		ctx->reference_count, ctx->reference_count + 1));
414 
415 	ctx->reference_count++;
416 }
417 
418 idn_converter_t
idn_resconf_getalternateconverter(idn_resconf_t ctx)419 idn_resconf_getalternateconverter(idn_resconf_t ctx) {
420 	assert(ctx != NULL);
421 
422 	TRACE(("idn_resconf_getalternateconverter()\n"));
423 
424 	return (idn_resconf_getidnconverter(ctx));
425 }
426 
427 idn_delimitermap_t
idn_resconf_getdelimitermap(idn_resconf_t ctx)428 idn_resconf_getdelimitermap(idn_resconf_t ctx) {
429 	assert(ctx != NULL);
430 
431 	TRACE(("idn_resconf_getdelimitermap()\n"));
432 
433 	if (ctx->delimiter_mapper != NULL)
434 		idn_delimitermap_incrref(ctx->delimiter_mapper);
435 	return (ctx->delimiter_mapper);
436 }
437 
438 idn_converter_t
idn_resconf_getidnconverter(idn_resconf_t ctx)439 idn_resconf_getidnconverter(idn_resconf_t ctx) {
440 	assert(ctx != NULL);
441 
442 	TRACE(("idn_resconf_getidnconverter()\n"));
443 
444 	if (ctx->idn_converter != NULL)
445 		idn_converter_incrref(ctx->idn_converter);
446 	return (ctx->idn_converter);
447 }
448 
449 idn_converter_t
idn_resconf_getauxidnconverter(idn_resconf_t ctx)450 idn_resconf_getauxidnconverter(idn_resconf_t ctx) {
451 	assert(ctx != NULL);
452 
453 	TRACE(("idn_resconf_getauxidnconverter()\n"));
454 
455 	if (ctx->aux_idn_converter != NULL)
456 		idn_converter_incrref(ctx->aux_idn_converter);
457 	return (ctx->aux_idn_converter);
458 }
459 
460 idn_converter_t
idn_resconf_getlocalconverter(idn_resconf_t ctx)461 idn_resconf_getlocalconverter(idn_resconf_t ctx) {
462 	assert(ctx != NULL);
463 
464 	TRACE(("idn_resconf_getlocalconverter()\n"));
465 
466 #ifdef WITHOUT_ICONV
467 	return NULL;
468 
469 #else /* WITHOUT_ICONV */
470 	if (update_local_converter(ctx) != idn_success)
471 		return (NULL);
472 
473 	idn_converter_incrref(ctx->local_converter);
474 	return (ctx->local_converter);
475 
476 #endif /* WITHOUT_ICONV */
477 }
478 
479 idn_mapselector_t
idn_resconf_getlocalmapselector(idn_resconf_t ctx)480 idn_resconf_getlocalmapselector(idn_resconf_t ctx) {
481 	assert(ctx != NULL);
482 
483 	TRACE(("idn_resconf_getlocalmapselector()\n"));
484 
485 	if (ctx->local_mapper != NULL)
486 		idn_mapselector_incrref(ctx->local_mapper);
487 	return (ctx->local_mapper);
488 }
489 
490 idn_mapper_t
idn_resconf_getmapper(idn_resconf_t ctx)491 idn_resconf_getmapper(idn_resconf_t ctx) {
492 	assert(ctx != NULL);
493 
494 	TRACE(("idn_resconf_getmapper()\n"));
495 
496 	if (ctx->mapper != NULL)
497 		idn_mapper_incrref(ctx->mapper);
498 	return (ctx->mapper);
499 }
500 
501 idn_normalizer_t
idn_resconf_getnormalizer(idn_resconf_t ctx)502 idn_resconf_getnormalizer(idn_resconf_t ctx) {
503 	assert(ctx != NULL);
504 
505 	TRACE(("idn_resconf_getnormalizer()\n"));
506 
507 	if (ctx->normalizer != NULL)
508 		idn_normalizer_incrref(ctx->normalizer);
509 	return (ctx->normalizer);
510 }
511 
512 idn_checker_t
idn_resconf_getprohibitchecker(idn_resconf_t ctx)513 idn_resconf_getprohibitchecker(idn_resconf_t ctx) {
514 	assert(ctx != NULL);
515 
516 	TRACE(("idn_resconf_getprohibitchecker()\n"));
517 
518 	if (ctx->prohibit_checker != NULL)
519 		idn_checker_incrref(ctx->prohibit_checker);
520 	return (ctx->prohibit_checker);
521 }
522 
523 idn_checker_t
idn_resconf_getunassignedchecker(idn_resconf_t ctx)524 idn_resconf_getunassignedchecker(idn_resconf_t ctx) {
525 	assert(ctx != NULL);
526 
527 	TRACE(("idn_resconf_getunassignedchecker()\n"));
528 
529 	if (ctx->unassigned_checker != NULL)
530 		idn_checker_incrref(ctx->unassigned_checker);
531 	return (ctx->unassigned_checker);
532 }
533 
534 idn_checker_t
idn_resconf_getbidichecker(idn_resconf_t ctx)535 idn_resconf_getbidichecker(idn_resconf_t ctx) {
536 	assert(ctx != NULL);
537 
538 	TRACE(("idn_resconf_getbidichecker()\n"));
539 
540 	if (ctx->bidi_checker != NULL)
541 		idn_checker_incrref(ctx->bidi_checker);
542 	return (ctx->bidi_checker);
543 }
544 
545 void
idn_resconf_setalternateconverter(idn_resconf_t ctx,idn_converter_t alternate_converter)546 idn_resconf_setalternateconverter(idn_resconf_t ctx,
547 				  idn_converter_t alternate_converter) {
548 	assert(ctx != NULL);
549 
550 	TRACE(("idn_resconf_setalternateconverter()\n"));
551 }
552 
553 void
idn_resconf_setdelimitermap(idn_resconf_t ctx,idn_delimitermap_t delimiter_mapper)554 idn_resconf_setdelimitermap(idn_resconf_t ctx,
555 			    idn_delimitermap_t delimiter_mapper) {
556 	assert(ctx != NULL);
557 
558 	TRACE(("idn_resconf_setdelimitermap()\n"));
559 
560 	if (ctx->delimiter_mapper != NULL)
561 		idn_delimitermap_destroy(ctx->delimiter_mapper);
562 	ctx->delimiter_mapper = delimiter_mapper;
563 	if (delimiter_mapper != NULL)
564 		idn_delimitermap_incrref(ctx->delimiter_mapper);
565 }
566 
567 void
idn_resconf_setidnconverter(idn_resconf_t ctx,idn_converter_t idn_converter)568 idn_resconf_setidnconverter(idn_resconf_t ctx,
569 			    idn_converter_t idn_converter) {
570 	assert(ctx != NULL);
571 
572 	TRACE(("idn_resconf_setidnconverter()\n"));
573 
574 	if (ctx->idn_converter != NULL)
575 		idn_converter_destroy(ctx->idn_converter);
576 	ctx->idn_converter = idn_converter;
577 	if (idn_converter != NULL)
578 		idn_converter_incrref(ctx->idn_converter);
579 }
580 
581 void
idn_resconf_setauxidnconverter(idn_resconf_t ctx,idn_converter_t aux_idn_converter)582 idn_resconf_setauxidnconverter(idn_resconf_t ctx,
583 				idn_converter_t aux_idn_converter) {
584 	assert(ctx != NULL);
585 
586 	TRACE(("idn_resconf_setauxidnconverter()\n"));
587 
588 	if (ctx->aux_idn_converter != NULL)
589 		idn_converter_destroy(ctx->aux_idn_converter);
590 	ctx->aux_idn_converter = aux_idn_converter;
591 	if (aux_idn_converter != NULL)
592 		idn_converter_incrref(ctx->aux_idn_converter);
593 }
594 
595 void
idn_resconf_setlocalconverter(idn_resconf_t ctx,idn_converter_t local_converter)596 idn_resconf_setlocalconverter(idn_resconf_t ctx,
597 			      idn_converter_t local_converter) {
598 #ifndef WITHOUT_ICONV
599 	assert(ctx != NULL);
600 
601 	TRACE(("idn_resconf_setlocalconverter()\n"));
602 
603 	if (ctx->local_converter != NULL) {
604 		idn_converter_destroy(ctx->local_converter);
605 		ctx->local_converter = NULL;
606 	}
607 
608 	if (local_converter == NULL)
609 		ctx->local_converter_is_static = 0;
610 	else {
611 		ctx->local_converter = local_converter;
612 		idn_converter_incrref(local_converter);
613 		ctx->local_converter_is_static = 1;
614 	}
615 #endif /* WITHOUT_ICONV */
616 }
617 
618 void
idn_resconf_setlocalmapselector(idn_resconf_t ctx,idn_mapselector_t local_mapper)619 idn_resconf_setlocalmapselector(idn_resconf_t ctx,
620 				idn_mapselector_t local_mapper) {
621 	assert(ctx != NULL);
622 
623 	TRACE(("idn_resconf_setlocalmapselector()\n"));
624 
625 	if (ctx->local_mapper != NULL)
626 		idn_mapselector_destroy(ctx->local_mapper);
627 	ctx->local_mapper = local_mapper;
628 	if (local_mapper != NULL)
629 		idn_mapselector_incrref(ctx->local_mapper);
630 }
631 
632 void
idn_resconf_setmapper(idn_resconf_t ctx,idn_mapper_t mapper)633 idn_resconf_setmapper(idn_resconf_t ctx, idn_mapper_t mapper) {
634 	assert(ctx != NULL);
635 
636 	TRACE(("idn_resconf_setmapper()\n"));
637 
638 	if (ctx->mapper != NULL)
639 		idn_mapper_destroy(ctx->mapper);
640 	ctx->mapper = mapper;
641 	if (mapper != NULL)
642 		idn_mapper_incrref(ctx->mapper);
643 }
644 
645 void
idn_resconf_setnormalizer(idn_resconf_t ctx,idn_normalizer_t normalizer)646 idn_resconf_setnormalizer(idn_resconf_t ctx, idn_normalizer_t normalizer) {
647 	assert(ctx != NULL);
648 
649 	TRACE(("idn_resconf_setnormalizer()\n"));
650 
651 	if (ctx->normalizer != NULL)
652 		idn_normalizer_destroy(ctx->normalizer);
653 	ctx->normalizer = normalizer;
654 	if (normalizer != NULL)
655 		idn_normalizer_incrref(ctx->normalizer);
656 }
657 
658 void
idn_resconf_setprohibitchecker(idn_resconf_t ctx,idn_checker_t prohibit_checker)659 idn_resconf_setprohibitchecker(idn_resconf_t ctx,
660 			       idn_checker_t prohibit_checker) {
661 	assert(ctx != NULL);
662 
663 	TRACE(("idn_resconf_setprohibitchecker()\n"));
664 
665 	if (ctx->prohibit_checker != NULL)
666 		idn_checker_destroy(ctx->prohibit_checker);
667 	ctx->prohibit_checker = prohibit_checker;
668 	if (prohibit_checker != NULL)
669 		idn_checker_incrref(ctx->prohibit_checker);
670 }
671 
672 void
idn_resconf_setunassignedchecker(idn_resconf_t ctx,idn_checker_t unassigned_checker)673 idn_resconf_setunassignedchecker(idn_resconf_t ctx,
674 				 idn_checker_t unassigned_checker) {
675 	assert(ctx != NULL);
676 
677 	TRACE(("idn_resconf_setunassignedchecker()\n"));
678 
679 	if (ctx->unassigned_checker != NULL)
680 		idn_checker_destroy(ctx->unassigned_checker);
681 	ctx->unassigned_checker = unassigned_checker;
682 	if (unassigned_checker != NULL)
683 		idn_checker_incrref(ctx->unassigned_checker);
684 }
685 
686 void
idn_resconf_setbidichecker(idn_resconf_t ctx,idn_checker_t bidi_checker)687 idn_resconf_setbidichecker(idn_resconf_t ctx,
688 			   idn_checker_t bidi_checker) {
689 	assert(ctx != NULL);
690 
691 	TRACE(("idn_resconf_setbidichecker()\n"));
692 
693 	if (ctx->bidi_checker != NULL)
694 		idn_checker_destroy(ctx->bidi_checker);
695 	ctx->bidi_checker = bidi_checker;
696 	if (bidi_checker != NULL)
697 		idn_checker_incrref(ctx->bidi_checker);
698 }
699 
700 idn_result_t
idn_resconf_setnameprepversion(idn_resconf_t ctx,const char * version)701 idn_resconf_setnameprepversion(idn_resconf_t ctx, const char *version)
702 {
703 	char prohibit_scheme_name[MAX_CONF_LINE_LENGTH + 1];
704 	char unassigned_scheme_name[MAX_CONF_LINE_LENGTH + 1];
705 	char bidi_scheme_name[MAX_CONF_LINE_LENGTH + 1];
706 	idn_mapper_t mapper = NULL;
707 	idn_normalizer_t normalizer = NULL;
708 	idn_checker_t prohibit_checker = NULL;
709 	idn_checker_t unassigned_checker = NULL;
710 	idn_checker_t bidi_checker = NULL;
711 	idn_result_t r;
712 
713 	assert(ctx != NULL && version != NULL);
714 
715 	TRACE(("idn_resconf_setnameprepversion()\n"));
716 
717 	/*
718 	 * Set canonical scheme names.
719 	 */
720 	if (strlen(version) + strlen(IDN_CHECKER_PROHIBIT_PREFIX)
721 	    > MAX_CONF_LINE_LENGTH) {
722 		r = idn_invalid_name;
723 		goto failure;
724 	}
725 	sprintf(prohibit_scheme_name, "%s%s",
726 	        IDN_CHECKER_PROHIBIT_PREFIX, version);
727 
728 	if (strlen(version) + strlen(IDN_CHECKER_UNASSIGNED_PREFIX)
729 	    > MAX_CONF_LINE_LENGTH) {
730 		r = idn_invalid_name;
731 		goto failure;
732 	}
733 	sprintf(unassigned_scheme_name, "%s%s",
734 	        IDN_CHECKER_UNASSIGNED_PREFIX, version);
735 
736 	if (strlen(version) + strlen(IDN_CHECKER_BIDI_PREFIX)
737 	    > MAX_CONF_LINE_LENGTH) {
738 		r = idn_invalid_name;
739 		goto failure;
740 	}
741 	sprintf(bidi_scheme_name, "%s%s",
742 	        IDN_CHECKER_BIDI_PREFIX, version);
743 
744 	/*
745 	 * Create objects.
746 	 */
747 	r = idn_mapper_create(&mapper);
748 	if (r != idn_success)
749 		goto failure;
750 	r = idn_normalizer_create(&normalizer);
751 	if (r != idn_success)
752 		goto failure;
753 	r = idn_checker_create(&prohibit_checker);
754 	if (r != idn_success)
755 		goto failure;
756 	r = idn_checker_create(&unassigned_checker);
757 	if (r != idn_success)
758 		goto failure;
759 	r = idn_checker_create(&bidi_checker);
760 	if (r != idn_success)
761 		goto failure;
762 
763 	r = idn_mapper_add(mapper, version);
764 	if (r != idn_success)
765 		goto failure;
766 	r = idn_normalizer_add(normalizer, version);
767 	if (r != idn_success)
768 		goto failure;
769 	r = idn_checker_add(prohibit_checker, prohibit_scheme_name);
770 	if (r != idn_success)
771 		goto failure;
772 	r = idn_checker_add(unassigned_checker, unassigned_scheme_name);
773 	if (r != idn_success)
774 		goto failure;
775 	r = idn_checker_add(bidi_checker, bidi_scheme_name);
776 	if (r != idn_success)
777 		goto failure;
778 
779 	/*
780 	 * Set the objects.
781 	 */
782 	idn_resconf_setmapper(ctx, mapper);
783 	idn_resconf_setnormalizer(ctx, normalizer);
784 	idn_resconf_setprohibitchecker(ctx, prohibit_checker);
785 	idn_resconf_setunassignedchecker(ctx, unassigned_checker);
786 	idn_resconf_setbidichecker(ctx, bidi_checker);
787 
788 	/*
789 	 * Destroy the objects.
790 	 */
791 	idn_mapper_destroy(mapper);
792 	idn_normalizer_destroy(normalizer);
793 	idn_checker_destroy(prohibit_checker);
794 	idn_checker_destroy(unassigned_checker);
795 	idn_checker_destroy(bidi_checker);
796 
797 	return (idn_success);
798 
799 failure:
800 	if (mapper != NULL)
801 		idn_mapper_destroy(mapper);
802 	if (normalizer != NULL)
803 		idn_normalizer_destroy(normalizer);
804 	if (prohibit_checker != NULL)
805 		idn_checker_destroy(prohibit_checker);
806 	if (unassigned_checker != NULL)
807 		idn_checker_destroy(unassigned_checker);
808 	if (bidi_checker != NULL)
809 		idn_checker_destroy(bidi_checker);
810 
811 	return (r);
812 }
813 
814 idn_result_t
idn_resconf_setalternateconvertername(idn_resconf_t ctx,const char * name,int flags)815 idn_resconf_setalternateconvertername(idn_resconf_t ctx, const char *name,
816 				      int flags) {
817 	assert(ctx != NULL && name != NULL);
818 
819 	TRACE(("idn_resconf_setalternateconvertername(name=%s, flags=%d)\n",
820 	      name, flags));
821 
822 	return (idn_success);
823 }
824 
825 idn_result_t
idn_resconf_setidnconvertername(idn_resconf_t ctx,const char * name,int flags)826 idn_resconf_setidnconvertername(idn_resconf_t ctx, const char *name,
827 				int flags) {
828 	idn_converter_t idn_converter;
829 	idn_result_t r;
830 
831 	assert(ctx != NULL && name != NULL);
832 
833 	TRACE(("idn_resconf_setidnconvertername(name=%s, flags=%d)\n",
834 	      name, flags));
835 
836 	r = idn_converter_create(name, &idn_converter, flags);
837 	if (r != idn_success)
838 		return (r);
839 
840 	if (ctx->idn_converter != NULL)
841 		idn_converter_destroy(ctx->idn_converter);
842 	ctx->idn_converter = idn_converter;
843 
844 	return (idn_success);
845 }
846 
847 idn_result_t
idn_resconf_setauxidnconvertername(idn_resconf_t ctx,const char * name,int flags)848 idn_resconf_setauxidnconvertername(idn_resconf_t ctx, const char *name,
849 				    int flags) {
850 	idn_converter_t aux_idn_converter;
851 	const char *old_name;
852 	idn_result_t r;
853 
854 	assert(ctx != NULL && name != NULL);
855 
856 	TRACE(("idn_resconf_setauxidnconvertername(name=%s, flags=%d)\n",
857 	      name, flags));
858 
859 	if (ctx->aux_idn_converter != NULL) {
860 	    old_name = idn_converter_localencoding(ctx->aux_idn_converter);
861 	    if (old_name != NULL && strcmp(old_name, name) == 0)
862 		return (idn_success);
863 	}
864 
865 	r = idn_converter_create(name, &aux_idn_converter, flags);
866 	if (r != idn_success)
867 		return (r);
868 
869 	if (ctx->aux_idn_converter != NULL)
870 		idn_converter_destroy(ctx->aux_idn_converter);
871 	ctx->aux_idn_converter = aux_idn_converter;
872 
873 	return (idn_success);
874 }
875 
876 idn_result_t
idn_resconf_setlocalconvertername(idn_resconf_t ctx,const char * name,int flags)877 idn_resconf_setlocalconvertername(idn_resconf_t ctx, const char *name,
878 				  int flags) {
879 #ifdef WITHOUT_ICONV
880 	return idn_failure;
881 
882 #else /* WITHOUT_ICONV */
883 	idn_converter_t local_converter;
884 	idn_result_t r;
885 
886 	assert(ctx != NULL);
887 
888 	TRACE(("idn_resconf_setlocalconvertername(name=%s, flags=%d)\n",
889 	      name == NULL ? "<null>" : name, flags));
890 
891 	if (ctx->local_converter != NULL) {
892 		idn_converter_destroy(ctx->local_converter);
893 		ctx->local_converter = NULL;
894 	}
895 	ctx->local_converter_is_static = 0;
896 
897 	if (name != NULL) {
898 		r = idn_converter_create(name, &local_converter, flags);
899 		if (r != idn_success)
900 			return (r);
901 		ctx->local_converter = local_converter;
902 		ctx->local_converter_is_static = 1;
903 	}
904 
905 	return (idn_success);
906 
907 #endif /* WITHOUT_ICONV */
908 }
909 
910 idn_result_t
idn_resconf_addalldelimitermapucs(idn_resconf_t ctx,unsigned long * v,int nv)911 idn_resconf_addalldelimitermapucs(idn_resconf_t ctx, unsigned long *v,
912 				  int nv) {
913 	idn_result_t r;
914 
915 	TRACE(("idn_resconf_addalldelimitermapucs(nv=%d)\n", nv));
916 
917 	if (ctx->delimiter_mapper == NULL) {
918 		r = idn_delimitermap_create(&(ctx->delimiter_mapper));
919 		if (r != idn_success)
920 			return (r);
921 	}
922 
923 	r = idn_delimitermap_addall(ctx->delimiter_mapper, v, nv);
924 	return (r);
925 }
926 
927 idn_result_t
idn_resconf_addalllocalmapselectornames(idn_resconf_t ctx,const char * tld,const char ** names,int nnames)928 idn_resconf_addalllocalmapselectornames(idn_resconf_t ctx, const char *tld,
929 					const char **names, int nnames) {
930 	idn_result_t r;
931 
932 	assert(ctx != NULL && names != NULL && tld != NULL);
933 
934 	TRACE(("idn_resconf_addalllocalmapselectorname(tld=%s, nnames=%d)\n",
935 	      tld, nnames));
936 
937 	if (ctx->local_mapper == NULL) {
938 		r = idn_mapselector_create(&(ctx->local_mapper));
939 		if (r != idn_success)
940 			return (r);
941 	}
942 
943 	r = idn_mapselector_addall(ctx->local_mapper, tld, names, nnames);
944 	return (r);
945 }
946 
947 idn_result_t
idn_resconf_addallmappernames(idn_resconf_t ctx,const char ** names,int nnames)948 idn_resconf_addallmappernames(idn_resconf_t ctx, const char **names,
949 			      int nnames) {
950 	idn_result_t r;
951 
952 	assert(ctx != NULL && names != NULL);
953 
954 	TRACE(("idn_resconf_addallmappername()\n"));
955 
956 	if (ctx->mapper == NULL) {
957 		r = idn_mapper_create(&(ctx->mapper));
958 		if (r != idn_success)
959 			return (r);
960 	}
961 
962 	r = idn_mapper_addall(ctx->mapper, names, nnames);
963 	return (r);
964 }
965 
966 idn_result_t
idn_resconf_addallnormalizernames(idn_resconf_t ctx,const char ** names,int nnames)967 idn_resconf_addallnormalizernames(idn_resconf_t ctx, const char **names,
968 				  int nnames) {
969 	idn_result_t r;
970 
971 	assert(ctx != NULL && names != NULL);
972 
973 	TRACE(("idn_resconf_addallnormalizername(nnames=%d)\n", nnames));
974 
975 	if (ctx->normalizer == NULL) {
976 		r = idn_normalizer_create(&(ctx->normalizer));
977 		if (r != idn_success)
978 			return (r);
979 	}
980 
981 	r = idn_normalizer_addall(ctx->normalizer, names, nnames);
982 	return (r);
983 }
984 
985 idn_result_t
idn_resconf_addallprohibitcheckernames(idn_resconf_t ctx,const char ** names,int nnames)986 idn_resconf_addallprohibitcheckernames(idn_resconf_t ctx, const char **names,
987 				       int nnames) {
988 	char long_name[MAX_CONF_LINE_LENGTH + 1];
989 	idn_result_t r;
990 	int i;
991 
992 	assert(ctx != NULL && names != NULL);
993 
994 	TRACE(("idn_resconf_addallprohibitcheckername(nnames=%d)\n", nnames));
995 
996 	if (ctx->prohibit_checker == NULL) {
997 		r = idn_checker_create(&(ctx->prohibit_checker));
998 		if (r != idn_success)
999 			return (r);
1000 	}
1001 
1002 	for (i = 0; i < nnames; i++, names++) {
1003 		if (strlen(*names) + strlen(IDN_CHECKER_PROHIBIT_PREFIX)
1004 			> MAX_CONF_LINE_LENGTH) {
1005 			return (idn_invalid_name);
1006 		}
1007 		strcpy(long_name, IDN_CHECKER_PROHIBIT_PREFIX);
1008 		strcat(long_name, *names);
1009 
1010 		r = idn_checker_add(ctx->prohibit_checker, long_name);
1011 		if (r != idn_success)
1012 			return (r);
1013 	}
1014 
1015 	return (idn_success);
1016 }
1017 
1018 idn_result_t
idn_resconf_addallunassignedcheckernames(idn_resconf_t ctx,const char ** names,int nnames)1019 idn_resconf_addallunassignedcheckernames(idn_resconf_t ctx, const char **names,
1020 					 int nnames) {
1021 	char long_name[MAX_CONF_LINE_LENGTH + 1];
1022 	idn_result_t r;
1023 	int i;
1024 
1025 	assert(ctx != NULL && names != NULL);
1026 
1027 	TRACE(("idn_resconf_addallunassignedcheckername(nnames=%d)\n",
1028 	      nnames));
1029 
1030 	if (ctx->unassigned_checker == NULL) {
1031 		r = idn_checker_create(&(ctx->unassigned_checker));
1032 		if (r != idn_success)
1033 			return (r);
1034 	}
1035 
1036 	for (i = 0; i < nnames; i++, names++) {
1037 		if (strlen(*names) + strlen(IDN_CHECKER_UNASSIGNED_PREFIX)
1038 			> MAX_CONF_LINE_LENGTH) {
1039 			return (idn_invalid_name);
1040 		}
1041 		strcpy(long_name, IDN_CHECKER_UNASSIGNED_PREFIX);
1042 		strcat(long_name, *names);
1043 
1044 		r = idn_checker_add(ctx->unassigned_checker, long_name);
1045 		if (r != idn_success)
1046 			return (r);
1047 	}
1048 
1049 	return (idn_success);
1050 }
1051 
1052 idn_result_t
idn_resconf_addallbidicheckernames(idn_resconf_t ctx,const char ** names,int nnames)1053 idn_resconf_addallbidicheckernames(idn_resconf_t ctx, const char **names,
1054 				   int nnames) {
1055 	char long_name[MAX_CONF_LINE_LENGTH + 1];
1056 	idn_result_t r;
1057 	int i;
1058 
1059 	assert(ctx != NULL && names != NULL);
1060 
1061 	TRACE(("idn_resconf_addallbidicheckername(nnames=%d)\n", nnames));
1062 
1063 	if (ctx->bidi_checker == NULL) {
1064 		r = idn_checker_create(&(ctx->bidi_checker));
1065 		if (r != idn_success)
1066 			return (r);
1067 	}
1068 
1069 	for (i = 0; i < nnames; i++, names++) {
1070 		if (strlen(*names) + strlen(IDN_CHECKER_BIDI_PREFIX)
1071 			> MAX_CONF_LINE_LENGTH) {
1072 			return (idn_invalid_name);
1073 		}
1074 		strcpy(long_name, IDN_CHECKER_BIDI_PREFIX);
1075 		strcat(long_name, *names);
1076 
1077 		r = idn_checker_add(ctx->bidi_checker, long_name);
1078 		if (r != idn_success)
1079 			return (r);
1080 	}
1081 
1082 	return (idn_success);
1083 }
1084 
1085 static idn_result_t
parse_conf(idn_resconf_t ctx,FILE * fp)1086 parse_conf(idn_resconf_t ctx, FILE *fp) {
1087 	char line[MAX_CONF_LINE_LENGTH + 1];
1088 	int lineno = 0;
1089 	char *argv[3];
1090 	int argc;
1091 	idn_result_t r;
1092 	int conf_mask = 0;
1093 
1094 	TRACE(("parse_conf()\n"));
1095 
1096 	/*
1097 	 * Parse config file.  parsing of 'idn-encoding' line is
1098 	 * postponed because 'alias-file' line must be processed
1099 	 * before them.
1100 	 */
1101 	while (fgets(line, sizeof(line), fp) != NULL) {
1102 		char *newline;
1103 
1104 		lineno++;
1105 		newline = strpbrk(line, "\r\n");
1106 		if (newline != NULL)
1107 			*newline = '\0';
1108 		else if (fgetc(fp) != EOF) {
1109 			ERROR(("libidnkit: too long line \"%-.30s\", "
1110 			       "line %d\n", line, lineno));
1111 			return (idn_invalid_syntax);
1112 		}
1113 
1114 		argc = split_args(line, argv, 2);
1115 		if (argc == -1) {
1116 			ERROR(("libidnkit: syntax error, line %d\n", lineno));
1117 			return (idn_invalid_syntax);
1118 		} else if (argc == 0 || argv[0][0] == '#') {
1119 			continue;
1120 		} else if (argc == 1) {
1121 			ERROR(("libidnkit: syntax error, line %d\n", lineno));
1122 			return (idn_invalid_syntax);
1123 		}
1124 
1125 		if (strcmp(argv[0], "idn-encoding") == 0) {
1126 			if (conf_mask & DEFAULT_CONF_IDN_ENCODING) {
1127 				ERROR(("libidnkit: \"%s\" redefined, "
1128 				       "line %d\n", argv[0], lineno));
1129 				r = idn_invalid_syntax;
1130 			} else {
1131 				conf_mask |= DEFAULT_CONF_IDN_ENCODING;
1132 				r = parse_idn_encoding(ctx, argv[1], lineno);
1133 			}
1134 		} else if (strcmp(argv[0], "local-map") == 0) {
1135 			r = parse_local_map(ctx, argv[1], lineno);
1136 
1137 		} else if (strcmp(argv[0], "nameprep") == 0) {
1138 			if (conf_mask & DEFAULT_CONF_NAMEPREP) {
1139 				ERROR(("libidnkit: \"%s\" redefined, "
1140 				       "line %d\n", argv[0], lineno));
1141 				r = idn_invalid_syntax;
1142 			} else {
1143 				conf_mask |= DEFAULT_CONF_NAMEPREP;
1144 				r = parse_nameprep(ctx, argv[1], lineno);
1145 			}
1146 		} else if (strcmp(argv[0], "nameprep-map") == 0 ||
1147 			   strcmp(argv[0], "nameprep-normalize") == 0 ||
1148 			   strcmp(argv[0], "nameprep-prohibit") == 0 ||
1149 			   strcmp(argv[0], "nameprep-unassigned") == 0 ||
1150 			   strcmp(argv[0], "alias-file") == 0 ||
1151 			   strcmp(argv[0], "encoding-alias-file") == 0 ||
1152 			   strcmp(argv[0], "normalize") == 0 ||
1153 			   strcmp(argv[0], "server-encoding") == 0 ||
1154 		           strcmp(argv[0], "alternate-encoding") == 0 ||
1155 			   strcmp(argv[0], "delimiter-map") == 0) {
1156 			WARNING(("libidnkit: obsolete command \"%s\", line %d "
1157 			         "(ignored)\n", argv[0], lineno));
1158 			r = idn_success;
1159 		} else {
1160 			ERROR(("libidnkit: unknown command \"%-.30s\", "
1161 			       "line %d\n", argv[0], lineno));
1162 			r = idn_invalid_syntax;
1163 		}
1164 		if (r != idn_success)
1165 			return (r);
1166 	}
1167 
1168 	lineno++;
1169 
1170 	if (conf_mask != DEFAULT_CONF_ALL) {
1171 		return setdefaults_body(ctx, conf_mask);
1172 	}
1173 
1174 	return (idn_success);
1175 }
1176 
1177 static idn_result_t
parse_idn_encoding(idn_resconf_t ctx,char * args,int lineno)1178 parse_idn_encoding(idn_resconf_t ctx, char *args, int lineno) {
1179 	idn_result_t r;
1180 	char *argv[MAX_CONF_LINE_ARGS + 1];
1181 	int argc;
1182 
1183 	argc = split_args(args, argv, MAX_CONF_LINE_ARGS + 1);
1184 
1185 	if (argc != 1) {
1186 		ERROR(("libidnkit: wrong # of args for idn-encoding, "
1187 		       "line %d\n", lineno));
1188 		return (idn_invalid_syntax);
1189 	}
1190 
1191 	r = idn_converter_create(argv[0], &ctx->idn_converter,
1192 				 IDN_CONVERTER_DELAYEDOPEN |
1193 				 IDN_CONVERTER_RTCHECK);
1194 	if (r != idn_success) {
1195 		ERROR(("libidnkit: cannot create idn converter, %s, "
1196 		       "line %d\n", idn_result_tostring(r), lineno));
1197 	}
1198 
1199 	return (r);
1200 }
1201 
1202 static idn_result_t
parse_local_map(idn_resconf_t ctx,char * args,int lineno)1203 parse_local_map(idn_resconf_t ctx, char *args, int lineno) {
1204 	idn_result_t r;
1205 	char *argv[MAX_CONF_LINE_ARGS + 1];
1206 	int argc;
1207 	int i;
1208 
1209 	argc = split_args(args, argv, MAX_CONF_LINE_ARGS + 1);
1210 
1211 	if (argc < 2 || argc > MAX_CONF_LINE_ARGS) {
1212 		ERROR(("libidnkit: wrong # of args for local-map, line %d\n",
1213 		       lineno));
1214 		return (idn_invalid_syntax);
1215 	}
1216 
1217 	if (ctx->local_mapper == NULL) {
1218 		r = idn_mapselector_create(&ctx->local_mapper);
1219 		if (r != idn_success) {
1220 			ERROR(("libidnkit: cannot create local mapper, %s, "
1221 			       "line %d\n", idn_result_tostring(r), lineno));
1222 			return (r);
1223 		}
1224 	}
1225 
1226 	for (i = 1; i < argc; i++) {
1227 		r = idn_mapselector_add(ctx->local_mapper, argv[0], argv[i]);
1228 		if (r == idn_invalid_name) {
1229 			ERROR(("libidnkit: map scheme unavailable \"%-.30s\""
1230 			       " or invalid TLD \"%-.30s\", line %d\n",
1231 			       argv[i], argv[0], lineno));
1232 			return (r);
1233 		} else if (r != idn_success) {
1234 			return (r);
1235 		}
1236 	}
1237 
1238 	return (idn_success);
1239 }
1240 
1241 static idn_result_t
parse_nameprep(idn_resconf_t ctx,char * args,int lineno)1242 parse_nameprep(idn_resconf_t ctx, char *args, int lineno) {
1243 	idn_result_t r;
1244 	char *argv[MAX_CONF_LINE_ARGS + 1];
1245 	char scheme_name[MAX_CONF_LINE_LENGTH + 1];
1246 	int argc;
1247 
1248 	argc = split_args(args, argv, MAX_CONF_LINE_ARGS + 1);
1249 
1250 	if (argc != 1) {
1251 		ERROR(("libidnkit: wrong # of args for nameprep, line %d\n",
1252 		       lineno));
1253 		return (idn_invalid_syntax);
1254 	}
1255 
1256 	/*
1257 	 * Set mapper.
1258 	 */
1259 	r = idn_mapper_create(&ctx->mapper);
1260 	if (r != idn_success) {
1261 		ERROR(("libidnkit: cannot create mapper, %s, line %d\n",
1262 		       idn_result_tostring(r), lineno));
1263 		return (r);
1264 	}
1265 
1266 	r = idn_mapper_add(ctx->mapper, argv[0]);
1267 	if (r == idn_invalid_name) {
1268 		ERROR(("libidnkit: map scheme unavailable \"%-.30s\", "
1269 		       "line %d\n", argv[0], lineno));
1270 		return (r);
1271 	} else if (r != idn_success) {
1272 		return (r);
1273 	}
1274 
1275 	/*
1276 	 * Set normalizer.
1277 	 */
1278 	r = idn_normalizer_create(&ctx->normalizer);
1279 	if (r != idn_success) {
1280 		ERROR(("libidnkit: cannot create normalizer, %s, line %d\n",
1281 		       idn_result_tostring(r), lineno));
1282 		return (r);
1283 	}
1284 
1285 	r = idn_normalizer_add(ctx->normalizer, argv[0]);
1286 	if (r == idn_invalid_name) {
1287 		ERROR(("libidnkit: unknown normalization scheme \"%-.30s\", "
1288 		       "line %d\n", argv[0], lineno));
1289 		return (r);
1290 	} else if (r != idn_success) {
1291 		return (r);
1292 	}
1293 
1294 	/*
1295 	 * Set prohibit checker.
1296 	 */
1297 	r = idn_checker_create(&ctx->prohibit_checker);
1298 	if (r != idn_success) {
1299 		ERROR(("libidnkit: cannot create prohibit checker, %s, "
1300 		       "line %d\n", idn_result_tostring(r), lineno));
1301 		return (r);
1302 	}
1303 
1304 	sprintf(scheme_name, "%s%s", IDN_CHECKER_PROHIBIT_PREFIX, argv[0]);
1305 	r = idn_checker_add(ctx->prohibit_checker, scheme_name);
1306 	if (r == idn_invalid_name) {
1307 		ERROR(("libidnkit: unknown prohibit scheme \"%-.30s\", "
1308 		       "line %d\n", argv[0], lineno));
1309 		return (r);
1310 	} else if (r != idn_success) {
1311 		return (r);
1312 	}
1313 
1314 	/*
1315 	 * Set unassigned checker.
1316 	 */
1317 	r = idn_checker_create(&ctx->unassigned_checker);
1318 	if (r != idn_success) {
1319 		ERROR(("libidnkit: cannot create unassigned checker, %s, "
1320 		       "line %d\n", idn_result_tostring(r), lineno));
1321 		return (r);
1322 	}
1323 
1324 	sprintf(scheme_name, "%s%s", IDN_CHECKER_UNASSIGNED_PREFIX, argv[0]);
1325 	r = idn_checker_add(ctx->unassigned_checker, scheme_name);
1326 	if (r == idn_invalid_name) {
1327 		ERROR(("libidnkit: unknown unassigned scheme \"%-.30s\", "
1328 		       "line %d\n", argv[0], lineno));
1329 		return (r);
1330 	} else if (r != idn_success) {
1331 		return (r);
1332 	}
1333 
1334 	/*
1335 	 * Set bidi checker.
1336 	 */
1337 	r = idn_checker_create(&ctx->bidi_checker);
1338 	if (r != idn_success) {
1339 		ERROR(("libidnkit: cannot create bidi checker, %s, line %d\n",
1340 		       idn_result_tostring(r), lineno));
1341 		return (r);
1342 	}
1343 
1344 	sprintf(scheme_name, "%s%s", IDN_CHECKER_BIDI_PREFIX, argv[0]);
1345 	r = idn_checker_add(ctx->bidi_checker, scheme_name);
1346 	if (r == idn_invalid_name) {
1347 		ERROR(("libidnkit: unknown bidi scheme \"%-.30s\", "
1348 		       "line %d\n", argv[0], lineno));
1349 		return (r);
1350 	} else if (r != idn_success) {
1351 		return (r);
1352 	}
1353 
1354 	return (idn_success);
1355 }
1356 
1357 static int
split_args(char * s,char ** av,int max_ac)1358 split_args(char *s, char **av, int max_ac) {
1359 	int ac;
1360 	int i;
1361 
1362 	for (ac = 0; *s != '\0' && ac < max_ac; ac++) {
1363 		if (ac > 0)
1364 			*s++ = '\0';
1365 		while (isspace((unsigned char)*s))
1366 			s++;
1367 		if (*s == '\0')
1368 			break;
1369 		if (*s == '"' || *s == '\'') {
1370 			int qc = *s++;
1371 			av[ac] = s;
1372 			while (*s != qc) {
1373 				if (*s == '\0')
1374 					return (-1);
1375 				s++;
1376 			}
1377 		} else {
1378 			av[ac] = s;
1379 			while (*s != '\0' && !isspace((unsigned char)*s))
1380 				s++;
1381 		}
1382 	}
1383 
1384 	for (i = ac; i < max_ac; i++)
1385 		av[i] = NULL;
1386 
1387 	return (ac);
1388 }
1389 
1390 static void
resetconf(idn_resconf_t ctx)1391 resetconf(idn_resconf_t ctx) {
1392 #ifndef WITHOUT_ICONV
1393 	idn_resconf_setlocalconverter(ctx, NULL);
1394 #endif
1395 	idn_resconf_setidnconverter(ctx, NULL);
1396 	idn_resconf_setauxidnconverter(ctx, NULL);
1397 	idn_resconf_setdelimitermap(ctx, NULL);
1398 	idn_resconf_setlocalmapselector(ctx, NULL);
1399 	idn_resconf_setmapper(ctx, NULL);
1400 	idn_resconf_setnormalizer(ctx, NULL);
1401 	idn_resconf_setprohibitchecker(ctx, NULL);
1402 	idn_resconf_setunassignedchecker(ctx, NULL);
1403 	idn_resconf_setbidichecker(ctx, NULL);
1404 }
1405 
1406 #ifndef WITHOUT_ICONV
1407 static idn_result_t
update_local_converter(idn_resconf_t ctx)1408 update_local_converter(idn_resconf_t ctx) {
1409 	idn_result_t r;
1410 	const char *old_encoding;
1411 	const char *new_encoding;
1412 
1413 	/*
1414 	 * We don't update local converter, if the converter is set
1415 	 * by idn_resconf_setlocalconverter() or
1416 	 * idn_resconf_setlocalconvertername().
1417 	 */
1418 	if (ctx->local_converter_is_static)
1419 		return (idn_success);
1420 
1421 	/*
1422 	 * Update the local converter if the local encoding is changed.
1423 	 */
1424 	old_encoding = (ctx->local_converter != NULL) ?
1425 		       idn_converter_localencoding(ctx->local_converter) :
1426 		       NULL;
1427 	new_encoding = idn_localencoding_name();
1428 	if (new_encoding == NULL) {
1429 		ERROR(("cannot determine local codeset name\n"));
1430 		return (idn_notfound);
1431 	}
1432 
1433 	if (old_encoding != NULL &&
1434 	    new_encoding != NULL &&
1435 	    strcmp(old_encoding, new_encoding) == 0) {
1436 		return (idn_success);
1437 	}
1438 
1439 	if (ctx->local_converter != NULL) {
1440 		idn_converter_destroy(ctx->local_converter);
1441 		ctx->local_converter = NULL;
1442 	}
1443 
1444 	r = idn_converter_create(new_encoding,
1445 				 &ctx->local_converter,
1446 				 IDN_CONVERTER_RTCHECK);
1447 	return (r);
1448 }
1449 #endif
1450 
1451 idn_result_t
idn_resconf_setdefaults(idn_resconf_t ctx)1452 idn_resconf_setdefaults(idn_resconf_t ctx)
1453 {
1454 	idn_result_t r;
1455 
1456 	assert(ctx != NULL);
1457 
1458 	TRACE(("idn_resconf_setdefaults()\n"));
1459 
1460 	resetconf(ctx);
1461 	r = idn_delimitermap_create(&ctx->delimiter_mapper);
1462 	if (r != idn_success) {
1463 		ERROR(("libidnkit: cannot create delimiter mapper, %s\n",
1464 		       idn_result_tostring(r)));
1465 		return (r);
1466 	}
1467 
1468 	return setdefaults_body(ctx, 0);
1469 }
1470 
1471 static idn_result_t
setdefaults_body(idn_resconf_t ctx,int conf_mask)1472 setdefaults_body(idn_resconf_t ctx, int conf_mask) {
1473 	idn_result_t r;
1474 
1475 	TRACE(("setdefaults_body()\n"));
1476 	assert(ctx != NULL);
1477 
1478 	if (!(conf_mask & DEFAULT_CONF_NAMEPREP)) {
1479 		TRACE(("set default nameprep\n"));
1480 		r = idn_resconf_setnameprepversion(ctx, IDN_NAMEPREP_CURRENT);
1481 		if (r != idn_success) {
1482 			return (r);
1483 		}
1484 	}
1485 	if (!(conf_mask & DEFAULT_CONF_IDN_ENCODING)) {
1486 		TRACE(("set default idn encoding\n"));
1487 		r = idn_converter_create(IDN_ENCODING_CURRENT,
1488 					 &ctx->idn_converter,
1489 					 IDN_CONVERTER_DELAYEDOPEN |
1490 					 IDN_CONVERTER_RTCHECK);
1491 		if (r != idn_success) {
1492 			ERROR(("libidnkit: cannot create idn converter, %s\n",
1493 			       idn_result_tostring(r)));
1494 			return (r);
1495 		}
1496 	}
1497 
1498 	return (idn_success);
1499 }
1500