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